perm filename EINIT.CMD[1,3]31 blob sn#699351 filedate 1983-03-24 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00018 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	⊂ Description of this file:
C00004 00003	⊂ REF		Horizontal attach and copy
C00006 00004	⊂ REF, DON	Reverse a line, reverse an FMUNGE character
C00008 00005	⊂ REF		Word transposition
C00009 00006	⊂ REF		Find in a list of files
C00010 00007	⊂ REF		Saving a readonly page
C00011 00008	⊂ REF		Convert a directory to file names
C00012 00009	⊂ REF, DON	Caps to small and back
C00013 00010	⊂ DON		Wait for file to be free
C00015 00011	⊂ DON, KS	Quicksort the lines on a page
C00026 00012	⊂ ROB, KS	BURP an entire file
C00029 00013	⊂ DON		Save/restore modes
C00036 00014	⊂ DON		Reply to mail
C00096 00015	⊂ DON		Archive a message
C00098 00016	⊂ DON		Purge selected pages from a file, such as BBOARD
C00105 00017	⊂ DON		Find out the name of the file being edited
C00108 00018	⊂ RSF		Send newly added BBOARD messages to "OTHER-SU-BBOARDS".
C00115 ENDMK
C⊗;
⊗⊂ Description of this file:

This is the system library of E macros.  Bug reports and (copiously commented)
additions should be sent to the current librarian via "MAIL EINIT", which will
forward appropriately.

All of the macros in this file can be used by loading the appropriate page with
the extended EXECUTE command.  (None require user mods.)  Thus, to get the
horizontal attachment and copying macros on the next page, one would type to E:
	<control>xEXE [1,3](3)<carriage return>

When you load in a page of macros this way, you'll be told the name(s) of the
principal macro(s) brought in.

Have fun!
⊗⊃
⊗⊂ REF		Horizontal attach and copy

These macros are for horizontal attachments.  Calling the macro HA inserts
a mark in the line (a <vt>), and aborts.  Resuming under another
character picks up everything from the original mark to that character,
and places it in the horizontal attachment buffer.  Doing a further
"resume", or calling the macros HD or HAB will deposit that text in a line.

Doing a deposit at the end of a line unfortunately leaves you in line
insert mode.

HC will do a copy, rather than an attach.  HSAVE will save your horizontal
attach buffer in the macro HD1.  Invoking the macro HD will also deposit
your horizontal attach buffer.
⊗⊃

αXDEFINE HA⊗↔
αi⊗←αs⊗←αxabort⊗↔β⊗←α⊗↑β⊗↔αβuαs⊗←αdβ⊗↔αβa⊗↔αβe
β⊗αβiα⊗=⊗αs⊗←α⊗↔αaαxred hab⊗↔αβk
αβuαβuαβxjo⊗↔αs⊗←αd
αβxabort⊗↔αβzhd⊗↔
αβ⊗↓

αXDEFINE HD⊗↔
αβzhab⊗↔αβ⊗↓

αXDEFINE HC⊗↔
αi⊗←αs⊗≠αxabort⊗↔
β⊗↔αβuαs⊗←αdβ⊗↔αi⊗αiα⊗=⊗αs⊗←α⊗↔αβaαβxred hab⊗↔αβeα2αdα⊗=⊗↑⊗↑⊗↑αβuαβ3αβxjo⊗↔αβxabort⊗↔
αβzhd⊗↔
αβ⊗↓

αXDEFINE HSAVE⊗↔
αβxatt hab⊗↔αβxred hab1⊗↔αβk
αβ⊗↓

αXDEFINE HD1⊗↔
αβzhab1⊗↔αβ⊗↓

αxsay HA HC ⊗↔
⊗⊂ REF, DON	Reverse a line, reverse an FMUNGE character

	The macro REVERSe reverses the current "arrow" line.  The line should
have at least two characters on it.

	If you're anywhere on a page of an FMUNGE star-dot file, the macro
CHRREV will reverse the character on that page.
⊗⊃

αXDEFINE revup⊗↔
αβ-αβa⊗↔
αβ⊗↓

⊗⊂ Point the arrow at the line to be reversed ⊗⊃
αXDEFINE REVERS⊗↔
αβaαβ1αβxbreak 1⊗↔αxargument attsiz.⊗↔αxset revlng⊗↔
αxargument revlng⊗↔αβzrevup⊗↔αxargument revlng⊗↔αβu
αxargument revlng⊗↔αβxjoin⊗↔
αβ⊗↓

αXDEFINE chrrv1⊗↔
⊗↔αzrevers⊗↔
αβ⊗↓

αXDEFINE CHRREV⊗↔
αlαxnonempty⊗↔αβuαxset revlng=lines.⊗↔
αxargument line.⊗↔αxsubtract revlng⊗↔αxargument revlng⊗↔αzchrrv1⊗↔
αβ⊗↓

αxsay REVERS CHRREV ⊗↔
⊗⊂ REF		Word transposition

	Move the cursor under the first of two words in the MIDDLE of
a line to be transposed, then execute TRANSP.
⊗⊃

αXDEFINE TRANSP⊗↔
β⊗↔αs α β⊗↔αs α β⊗↔	⊗; break the line around the two words
αβ-αβaαβuαβe		⊗; grab the second and move it up ahead of the first
αβuαβ3αβxjo⊗↔		⊗; go up a line and re-patch the world
α⊗=αd			⊗; pick up last part of last line, leaving cursor in useful place
αβ⊗↓

αxsay TRANSP ⊗↔
⊗⊂ REF		Find in a list of files

Do an extended FIND command to establish a search string.  Then take the
cursor and point it to the first of a list of files (one to a line), and
execute FLFIND.  The files will be searched in sequence until either the
next blank line in the list of names, or until the current string is
found.
⊗⊃

αXDEFINE FLFIND⊗↔
	αxstopone⊗↔αxsilent⊗↔αxterse⊗↔
	α∞αzflfnd1⊗↔
	αxstopall⊗↔α-αxsilent⊗↔α-αxterse⊗↔
αβ⊗↓

αXDEFINE FLFND1⊗↔
	αβ0αxnonempty⊗↔αxpoint /-r/2p/1l⊗↔
	αzflfnd2⊗↔αh⊗↔
αβ⊗↓

αXDEFINE FLFND2⊗↔
	αvαβ*
	α2αxabort⊗↔
αβ⊗↓

αxsay FLFIND ⊗↔
⊗⊂ REF		Saving a readonly page

It's often useful to be able to save the world (write out the in-core pages)
when in readonly mode, by leaving readonly mode, saving, and then returning.
This macro turns it into one command.
⊗⊃

αXDEFINE SAVE⊗↔
	αXREADWRITE⊗↔αβ.αXREADONLY⊗↔
αβ⊗↓

αxSAY SAVE ⊗↔
⊗⊂ REF		Convert a directory to file names

FIXFIL takes a page of directory information from WILD or DIR, and converts
it to a list of file names, one to a line.  Useful for editing directories.
⊗⊃

αXDEFINE FFIL⊗↔
α6α .α3α [α3α β,α3α ]αK⊗↔⊗↔αβ⊗↓

αXDEFINE FIXFIL⊗↔
αβLαβxarg lines.⊗↔αβZFFIL⊗↔
αβLαF αβ\αβ∞⊗↔αβLαβ⊗↓

αxSAY FIXFIL ⊗↔
⊗⊂ REF, DON	Caps to small and back

CTS changes a single capital letter to a small letter; STC does the inverse.
⊗⊃

αXDEFINE CTS⊗↔
	αxsilent⊗↔αxterse⊗↔αxstopone⊗↔αβ9αβ6αxset ctsval⊗↔
	αβ#αzctschk⊗↔α-αxterse⊗↔αxstopall⊗↔α-αxsilent⊗↔
αβ⊗↓

αXDEFINE STC⊗↔
	αxsilent⊗↔αxterse⊗↔αxstopone⊗↔αβ6αβ4αxset ctsval⊗↔
	αβ#αzctschk⊗↔α-αxterse⊗↔αxstopall⊗↔α-αxsilent⊗↔
αβ⊗↓

αXDEFINE CTSCHK⊗↔
	αzctsck1⊗↔α 
αβ⊗↓

αXDEFINE CTSCK1⊗↔
	αβ6αβ4αβxiflt ascii.⊗↔αxset ctschr=ascii.⊗↔αβ3αβ2αxremainder ctschr⊗↔
	αβ2αβ6αβxifge ctschr⊗↔αxifle ctschr⊗↔
	αβxargument ctsval⊗↔αxadd ctschr⊗↔αβxcharacter ctschr⊗↔α⊗↑
αβ⊗↓

αxsay CTS STC ⊗↔
⊗⊂ DON		Wait for file to be free

The OPEN macro will try once per second to open the file for writing.  When
the file is no longer in use by other people it will succeed, at which point
it prints a message to that effect and breedles the terminal.  At each
unsuccessful attempt it prints the list of people using the file; this
cannot be suppressed, so consider it a feature.
⊗⊃

αXDEFINE OPEN⊗↔
	αxstopone⊗↔αxsilent⊗↔αxterse⊗↔α∞αzopen2⊗↔α-αxterse⊗↔α-αxsilent⊗↔αxstopall⊗↔
αβ⊗↓

αXDEFINE OPEN2⊗↔
	αzopen3⊗↔α1αv
αβ⊗↓

αXDEFINE OPEN3⊗↔
	αxopen⊗↔αxsay File now open for writing. ⊗↔αxbeep⊗↔α2αxabort⊗↔
αβ⊗↓

αxSAY OPEN ⊗↔
⊗⊂ DON, KS	Quicksort the lines on a page

	The macro QSORT takes all lines on the current page (which may be one
of several incore pages) and sorts them based on a collating sequence determined
by the QCHMAP macro.  (The QCHMAP macro provided below simply maps lower-case
letters to their upper-case equivalents.)  The field sorted on is the entire
line; someday there may be facilities for specifying character positions, but
it doesn't really seem worth it.  Note: Lines which match on the first several
characters will be assumed equal and will be left unsorted (since the sort is
"stable", their relative order will be unchanged).  You'll be told if this
happens.

	QSORT is reasonably fast for small pages, say up to 100 lines or so.
Above that and the SSORT or MSORT program is probably your best bet.  QSORT
should have no side effects ("marks" unchanged, modes restored, etc.).

	QSORT updates the screen after each partitioning to give you something
to watch while it's working.  If you don't want this (especially if you're
invoking QSORT from another macro and don't want to be bothered), execute the
QNOSHO macro before invoking QSORT.
⊗⊃

⊗⊂	First step is to separate any empty lines, to save special-case
	testing in low-level routines.  Then we start recursion via QSORT1.
⊗⊃
αXDEFINE QSORT⊗↔
	αZENTRYX⊗↔α-αXUNDELETE⊗↔
	αXSET QRAPID=RAPID.⊗↔α-αXMAXIMUM QRAPID⊗↔αβ0αXMINIMUM QRAPID⊗↔
	αβ2αXMULTIPLY QRAPID⊗↔αXADD QRAPID⊗↔
	αXRAPID⊗↔
	α0αXSET QLEVEL⊗↔
	αLβ⊗→β⊗↔α-αAα∞αZQEMPTY⊗↔⊗↔α-αPαEαβDαP
	αZQSORT1⊗↔
	αLα-αβD
	αβXARGUMENT QRAPID⊗↔αXRAPID⊗↔
	αZEXIT⊗↔
αβ⊗↓

⊗⊂	QEMPTY looks for an empty line and appends it onto the attach buffer.
	We first back up so that (a) we'll find the second of two consecutive
	blank lines and (b) we won't go to the next incore page (X EMPTY does
	so if given at end of page).
⊗⊃
αXDEFINE QEMPTY⊗↔
	αUαXEMPTY⊗↔α+αA
αβ⊗↓

⊗⊂	QSORT1 is the top recursive call; it sorts the current page based on the
	first char of each line, and uses QEQUAL to subsort on equality.  It returns
	at once if there are fewer than 2 lines, else it uses the median line to
	partition the other lines into 3 subpages and recurses.
⊗⊃
αXDEFINE QSORT1⊗↔
	αXIFLT LINES.⊗↔
	α∞αLβ⊗→α-αPβ⊗→
	αXSET QVALUE←LINES.⊗↔α2αXDIVIDE QVALUE⊗↔
	αXARGUMENT QVALUE⊗↔⊗↔
	αZQSHOW⊗↔
	αXARGUMENT ASCII.⊗↔αZQCHMAP⊗↔αXSET QVALUE⊗↔
	αLαXARGUMENT LINES.⊗↔αZQSPLIT⊗↔
	α-αPαZQSORT1⊗↔
	αPαZQEQUAL⊗↔αLα-αβD
	αPαZQSORT1⊗↔
	αLα-αβD
αβ⊗↓

⊗⊂	QSPLIT compares the first char of the current line with QVALUE and moves
	the line to the appropriate subpage.
⊗⊃
αXDEFINE QSPLIT⊗↔
	αXARGUMENT ASCII.⊗↔αZQCHMAP⊗↔αXSET QVAL2⊗↔
	⊗↔
	αZQSPLT0⊗↔
αβ⊗↓

⊗⊂	QSPLT0 decides where to put the line above us, whose QLEVELth char is QVAL2.
⊗⊃
αXDEFINE QSPLT0⊗↔
	αXARGUMENT QVAL2⊗↔αXIFNE QVALUE⊗↔
	α-αAαXSET QLINE←LINE.⊗↔
	αZQLESS⊗↔
	αPα∞αLαE
	α-αPαXARGUMENT QLINE⊗↔αL
αβ⊗↓

⊗⊂	QLESS moves the line above us to the previous page if QVAL2 < QVALUE, and
	also aborts our caller (QSPLT0) if that's the case.
⊗⊃
αXDEFINE QLESS⊗↔
	αXARGUMENT QVAL2⊗↔αXIFLT QVALUE⊗↔
	αLαUαE
	αPαXARGUMENT QLINE⊗↔αL
	α2αXABORT⊗↔
αβ⊗↓

⊗⊂	QEQUAL is called to subsort a page on which all lines are, so far, equal.
	It aborts at once if there's only one line, else it increments QLEVEL,
	snarfs all lines which contain only QLEVEL chars (just as QSORT snarfed all
	empty lines), and calls QSORT2 to sort the rest.
⊗⊃
αXDEFINE QEQUAL⊗↔
	αXIFLT LINES.⊗↔
	αXADD QLEVEL⊗↔
	αLβ⊗→αCαUαXARGUMENT LINES.⊗↔αZQSNARF⊗↔α-αPαEαβDαP
	αZQSORT2⊗↔
	αLα-αβD
	αXSUBTRACT QLEVEL⊗↔
αβ⊗↓

⊗⊂	QSNARF and QSNRF0 attaches the current line if it has only QLEVEL chars.
⊗⊃
αXDEFINE QSNARF⊗↔
	αZQSNRF0⊗↔
	⊗↔
αβ⊗↓
αXDEFINE QSNRF0⊗↔
	αXARGUMENT QLEVEL⊗↔αXIFGE CHARS.⊗↔
	α+αAαU
αβ⊗↓

⊗⊂	QSORT2 is the secondary recursive call; it sorts the current page based on
	the QLEVELth char of each line, and uses QEQUAL to subsort on equality.  It
	returns at once if there are fewer than 2 lines, else it uses the median
	line to partition the other lines into 3 subpages and recurses.
⊗⊃
αXDEFINE QSORT2⊗↔
	αXIFLT LINES.⊗↔
	αZQDEEP⊗↔
	α∞αLβ⊗→α-αPβ⊗→
	αXSET QVALUE←LINES.⊗↔α2αXDIVIDE QVALUE⊗↔
	αXARGUMENT QVALUE⊗↔⊗↔
	αZQSHOW⊗↔
	αZQEVAL⊗↔
	αLαXARGUMENT LINES.⊗↔αZQSPLT2⊗↔
	α-αPαZQSORT2⊗↔
	αPαZQEQUAL⊗↔αLα-αβD
	αPαZQSORT2⊗↔
	αLα-αβD
αβ⊗↓

⊗⊂	QDEEP tests whether we're getting too deep in recursion due to lines which
	match on a long leading string.  For now, if so, we leave the lines unsorted
	and issue a warning.
⊗⊃
αXDEFINE QDEEP⊗↔
	α2α0αXIFLE QLEVEL⊗↔
	αXARGUMENT LINES.⊗↔αXSAY WARNING!! ⊗↔
	αXARGUMENT QLEVEL⊗↔αXSAY  lines match on their first ⊗↔
	αβXSAY  chars and are left unsorted.⊗↔
	α2αXABORT⊗↔
αβ⊗↓

⊗⊂	QEVAL and QEVL0 figure out what the character is that's QLEVEL chars in on
	the current line, and leaves us one the line below.  It uses the line-editor
	if possible, since it's faster, but if it won't fit it uses cruder methods.
	The value is put into QVALUE.
⊗⊃
αXDEFINE QEVAL⊗↔
	αZQEVL0⊗↔
	αCα1αXBREAK 1⊗↔αXARGUMENT QLEVEL⊗↔αβKα∞αXJOIN⊗↔αE
	αXARGUMENT ASCII.⊗↔αZQCHMAP⊗↔αXSET QVALUE⊗↔αβD
αβ⊗↓
αXDEFINE QEVL0⊗↔
	αXLETEST⊗↔
	αXARGUMENT QLEVEL⊗↔α αXARGUMENT ASCII.⊗↔αZQCHMAP⊗↔αXSET QVALUE⊗↔⊗↔
	α2αXABORT⊗↔
αβ⊗↓

⊗⊂	QSPLT2 is like QSPLIT except it looks at the QLEVELth char.
⊗⊃
αXDEFINE QSPLT2⊗↔
	αZQEVAL2⊗↔
	αZQSPLT0⊗↔
αβ⊗↓

⊗⊂	QEVAL2 and QEVL02 are the same as QEVAL except the value goes into QVAL2.
⊗⊃
αXDEFINE QEVAL2⊗↔
	αZQEVL02⊗↔
	αCα1αXBREAK 1⊗↔αXARGUMENT QLEVEL⊗↔αβKα∞αXJOIN⊗↔αE
	αXARGUMENT ASCII.⊗↔αZQCHMAP⊗↔αXSET QVAL2⊗↔αβD
αβ⊗↓
αXDEFINE QEVL02⊗↔
	αXLETEST⊗↔
	αXARGUMENT QLEVEL⊗↔α αXARGUMENT ASCII.⊗↔αZQCHMAP⊗↔αXSET QVAL2⊗↔⊗↔
	α2αXABORT⊗↔
αβ⊗↓

⊗⊂	QCHMAP takes its argument (via the rep count) and maps it into a new value
	based on the collating sequence desired.  The result is returned by ending
	QCHMAP with an ARGUMENT command.  This particular version of QCHMAP simply
	converts lower-case letters to upper-case.  NOTE: Be sure to use doublebucky
	on numeric arguments in QCHMAP, since it's called from the line editor.
⊗⊃
αXDEFINE QCHMAP⊗↔
	α#αXSET QCHARX⊗↔
	αβ1αβ2αβ3αXREMAINDER QCHARX⊗↔
	αβ9αβ7αXDIVIDE QCHARX⊗↔
	αβ-αβ3αβ2αXMULTIPLY QCHARX⊗↔
	α#αXARGUMENT QCHARX⊗↔
αβ⊗↓

⊗⊂	QORDLT is used by QORDER to test for QCHAR1 being less than QCHAR2.  If
	so, we abort to QLESS, else we return.
⊗⊃
αXDEFINE QORDLT⊗↔
	αXARGUMENT QCHAR1⊗↔αXIFLT QCHAR2⊗↔
	α2αβD
	α5αXABORT⊗↔
αβ⊗↓

⊗⊂	QSHOW just updates the screen.  It's done in a macro so that QNOSHO can
	turn it off (by making it do an altmode instead).
⊗⊃
αXDEFINE QSHOW⊗↔
	αV
αβ⊗↓
αXDEFINE QSHOW0⊗↔
	⊗≠
αβ⊗↓
αXDEFINE QNOSHO⊗↔
	αXSET QSHOW←QSHOW0⊗↔
αβ⊗↓

αxsay QSORT ⊗↔

⊗⊂ And we'll be needing ENTRY/EXIT macros: ⊗⊃	αXEXECUTE EINIT.CMD[1,3](13)⊗↔
⊗⊂ ROB, KS	BURP an entire file

(Original idea and simple minded implementation by ROB, all the niceness
 by KS.)

The BELCH macro `burps' an entire file, using the /∞F file switching
trick.  When finished, it announces the number of records in the file
before and after BELCHing, and the number of disk tracks thus freed.

Side effects:	A jump is made to the directory page, and the page stack
		will reflect that.  Macros named BEFORE, AFTER, SAVED,
		TRACKS, and SAYER are created (or altered).
⊗⊃

αXDEFINE BELCH⊗↔
	α1αPα∞αL⊗↑⊗↑			⊗; Go to directory page, ENDMK line
	αCαβXBREAK 1⊗↔αβ1αβK		⊗; Flush "C" from record number
	αβXBREAK 5⊗↔αβ-αβC		⊗; Flush other junk, move up
	αXREDEFINE BEFORE⊗↔αβK		⊗; Define BEFORE as old total records
	αβ1αβXSUBTRACT BEFORE⊗↔		⊗; Flush leading zeros, adjust number
	αε/∞F⊗↔				⊗;  BURP entire file
	αCαβXBREAK 1⊗↔αβ1αβK		⊗; Flush "C" from record number
	αβXBREAK 5⊗↔αβ-αβC		⊗; Flush other junk, move up
	αXREDEFINE AFTER⊗↔αβK		⊗; Define AFTER as new total records
	αβ1αβXSUBTRACT AFTER⊗↔		⊗; Flush leading zeros, adjust number
	αXSET SAVED←BEFORE⊗↔		⊗; Calculate savings in records
	αXARGUMENT AFTER⊗↔αXSUBTRACT SAVED⊗↔
	αXSET TRACKS←BEFORE⊗↔		⊗; Calculate track savings
	αβ1αβ7αXADD TRACKS⊗↔
	αβ1αβ8αXDIVIDE TRACKS⊗↔
	αXSET TRKAFT←AFTER⊗↔
	αβ1αβ7αXADD TRKAFT⊗↔
	αβ1αβ8αXDIVIDE TRKAFT⊗↔
	αXARGUMENT TRKAFT⊗↔αXSUBTRACT TRACKS⊗↔
	αO				⊗; Go back where we was
	αβI				⊗; Make a place to type
	⊗α⊗βXSAY Before: αβZBEFORE⊗↔	⊗; Type "αβXSAY Before:"&BEFORE
		. After: αβZAFTER⊗↔	⊗; Type ". After:"&AFTER
		. Saved recs: αβZSAVED⊗↔	⊗; Type ". Saved recs:"&SAVED
		. (tracks: αβZTRACKS⊗↔)⊗⊗↔	⊗; Type "("&TRACKS&" tracks)⊗↔"
	αAαXREDEFINE SAYER⊗↔		⊗; Now make a macro out of this
	αEαXCANCEL⊗↔			⊗; And cover our tracks
	αZSAYER⊗↔			⊗; Say it all
αβ⊗↓

αxsay BELCH ⊗↔
⊗⊂ DON		Save/restore modes

	ENTRY and EXIT save and restore states often modified by other macros.
Macro ENTRY saves the state of the CHECK, TERSE/VERBOSE, SILENT, UNDELETE, EXACT
and STOPHOW commands.  Macro EXIT restores them to the values saved by ENTRY.
(EXIT works regardless of the state of the flags when called.)  EXIT assumes
that the attach buffer is available for use; i.e., there's nothing in the attach
buffer and you're not in the line editor.  If this isn't true when your macro
exits, then call EXIT1 at some point where it IS true; then call EXIT2 at the
end of your macro.

	Note: Since the UNDELETE command (even with negative arg) is illegal in
the line editor, EXIT1 restores the UNDELETE setting.  So be sure to wait till
the last minute to call EXIT1 if you think this'll affect you.

	Macro ENTRYX is the same as ENTRY but also changes the modes to -CHECK,
TERSE, SILENT, -EXACT, and STOPONE.  (It leaves the UNDELETE size alone since
you might be in the line editor.)

	If a macro using ENTRY/EXIT in turn calls another macro that does so,
the "secondary" calls are ignored.  (ENTRYX still sets modes as given above.)
Thus, when the second-level macro exits, it will not have restored the state in
use by the top-level one.  Usually, however, the states set up by the two macros
will be compatible (especially if both use ENTRYX); if not, the top-level macro
should be careful to restore the state it wants when the other macro finishes.
This may get cleaned up someday using some sort of stack arrangement.

	These macros use, as variables, the macros named ENTRYC, ENTRYT, ENTRYS,
ENTRYU, ENTRYE, and ENTRYH, respectively.  ENTRYN is used to count the nesting
of ENTRY/EXIT calls to prevent second-level invocations destroying the data
saved at the top level.  The macros also use EXITW to save the state of the W
flag so they can know whether to do a CANCEL, and for other temporary storage.
⊗⊃

αXDEFINE ENTRY⊗↔
	αxset exitw=entryn⊗↔αxadd entryn⊗↔	⊗; check nesting depth
	αxminimum exitw⊗↔αβ0αxmaximum exitw⊗↔	⊗; can't use IFEQ 0 since STOPHOW is sacred
	αβxargument exitw⊗↔αxabort⊗↔
	αxset entryc=check.⊗↔αβ0αxminimum entryc⊗↔α-αxmaximum entryc⊗↔
		αβ2αxmultiply entryc⊗↔αxadd entryc⊗↔		⊗; +1=check, else -1
	αxset entryt=terse.⊗↔α-αxmaximum entryt⊗↔αxminimum entryt⊗↔
		αβ2αxadd entryt⊗↔			⊗; 1=terse, 2=normal, 3=verbose
	αxset entrys=silent.⊗↔αβ0αxmaximum entrys⊗↔αxminimum entrys⊗↔
		αβ2αxmultiply entrys⊗↔αxsubtract entrys⊗↔	⊗; +1=silent, else -1
	αxset entryu=undmax.⊗↔α-αxmultiply entryu⊗↔		⊗; -size of undelete buffer
	αxset entrye=exact.⊗↔αβ0αxmaximum entrye⊗↔α-αxminimum entrye⊗↔
		αβ2αxmultiply entrye⊗↔αxsubtract entrye⊗↔	⊗; +1=exact, else -1
	αxset entryh=stopho.⊗↔αβ2αxadd entryh⊗↔	⊗; 1=stopall, 2=stopzero, 3=stopone
αβ⊗↓

αXDEFINE ENTRYX⊗↔
	αzentry⊗↔
	αxterse⊗↔αxsilent⊗↔αxstopone⊗↔α-αxcheck⊗↔α-αxexact⊗↔
αβ⊗↓

αXDEFINE EXIT⊗↔
	αzexit1⊗↔αzexit2⊗↔
αβ⊗↓

αXDEFINE EXIT1⊗↔
	αxset exit2←exit2q⊗↔			⊗; null EXIT2 macro in case ENTRYN > 1
	αxsubtract entryn⊗↔αβ0αxmaximum entryn⊗↔αxset exitw=entryn⊗↔
	αxminimum exitw⊗↔αβxargument exitw⊗↔αxabort⊗↔	⊗; go away if not top-level
	αxset exitw=wflag.⊗↔αxadd exitw⊗↔	⊗; 1=page unchanged, else 2
	αβxargument entryu⊗↔αxundelete⊗↔	⊗; restore undelete size (can't wait for EXIT2)
	α2αβ⊗↔				⊗; create EXIT2 macro  (eschew insert mode to defeat autowrite)
		⊗α⊗βxargument entryc⊗⊗↔⊗αxcheck⊗⊗↔	⊗; restore free-storage check mode
		⊗α⊗βxargument entrye⊗⊗↔⊗αxexact⊗⊗↔	⊗; restore exactness of searches
		⊗α⊗βxargument entrys⊗⊗↔⊗αxsilent⊗⊗↔	⊗; restore silence mode
		⊗↔			⊗; keep lines short to stifle E's echoing bug
		⊗αxstop:=all=zero=one=αb:αβxargument entryh⊗↔αk=
			αdαs=αk⊗↔⊗⊗↔		⊗; restore stophow setting
		:=⊗αxterse=⊗α-⊗αxterse=⊗αxverbose=αb:αβxargument entryt⊗↔αk=
			αdαs=αk⊗↔⊗⊗↔		⊗; restore terse/verbose mode
	αβuαβ2αβaαxredefine exit2⊗↔αβk
	α1αβ⊗↔				⊗; create macro to do CANCEL if necessary (else altmode)
		:=⊗αxcancel⊗⊗↔=⊗⊗≠=αb:αβxargument exitw⊗↔αk=αdαs=αk⊗↔
	αβaαxredefine exitw⊗↔αβk	⊗; can reuse name EXITW for this
	αzexitw⊗↔
αβ⊗↓

αXDEFINE EXIT2Q⊗↔
	αx⊗↔
αβ⊗↓

αβ0αXSET ENTRYN⊗↔

αxsay ENTRY/EXIT ⊗↔
⊗⊂ DON		Reply to mail

	The REPLY macro makes it possible to send mail to whoever sent you a
particular piece of mail, without your having to type the network address or the
subject.  You can also (optionally) include copies to all recipients of the
original message (optionally excluding "cc" recipients).

	The basic operation of the macro is a three-step process.  First, you
execute the REPLY macro.  This sets up various headings based on the message on
the current page.  (It's okay to have more than one in-core page, but results
are unspecified if there are multiple messages on one page.)  The headings
should be self-explanatory.  At the bottom of the page is the "reply text",
which is initially set up to be a line saying when the incoming message was sent
(if known) or received (if not).  NOTE:  If you have anything in the attach
buffer when you execute REPLY, the buffer set down as part of the reply text.

	Having executed REPLY, you then edit the resulting template to add or
delete recipients and/or change the message text or subject.  (Additional
recipients should be entered one per line with one of the prefaces "Also-To:"
or "Reply-cc:".)  The only fields that must not be deleted entirely are the
"Replying-To" field (which must come first) and the "Reply-Text" field (which
must come last).

	When you're done editing the message, you then type <control>% to
execute the % macro set up by REPLY (you're reminded of this by REPLY).  This
sends the mail and restores the page to its original state.

	If, after executing REPLY, you decide you don't really want to send
the reply at all, just do a CANCEL (or delete all the reply-related stuff).

	To include all recipients of the original message on the mailing list
for the reply, execute the REPLY macro with an argument greater than 1.  E.g.,
<control>2<control>ZREPLY<cr>.  To include all but the "cc" recipients, give an
argument of "+", i.e., <control>+<control>ZREPLY<cr>.  Doing either of these
also causes the initial reply-text to include the name of the original sender.
People listed as having received "remailed" copies of the message are considered
to be "cc" recipients.

	Notes on operation:  REPLY makes a good try at parsing the more common
of the hairy contructs permitted under RFC733, the document defining network
mail protocols.  Quoted strings, parenthesised comments, and broketed network
addresses are all handled correctly.  If the recipient list of the original
message lacks some host-names, the host of the original sender is assumed (some
sites' mailers fail to put full network addresses for "local" addressees), or
the host of the first "Remailed-from" entry, if the original sender has no host
specified.  Foreign distribution-list files will probably be parsed correctly,
but the mail command will fail, since you can't access such files from here.
Local distribution lists, file destinations (#<file> construct), and forwarding
names (such as BUG-xxxx) should work.

	During the "editing" phase (after executing REPLY but before executing
"%" to send the mail), the following three macros may be useful (they are loaded
in along with REPLY):  CCME adds a "Reply-cc" to yourself.  TOLIST deletes the
"Replying-To" line and changes the next line from "Also-To" or "Reply-cc" into
the Replylng-To line (this is for when the original message was sent to a
distribution list by someone on that list, and you want to reply to the list
without shipping the original sender an extra copy).  OLDMSG appends the entire
text of the original message (header and all) to the end of the Reply-Text,
indented and set off by lines of hyphens.

	If the mailing list is too large for E's command buffer (current limit
is about 160 characters), the % macro will create a temporary distribution-list
file and delete it after the mail is sent.  This requires switching files, so
any changes made BEFORE executing REPLY will get written out -- the changes made
BY the REPLY macro are undone before switching.  (If you're in READONLY mode,
then ALL changes are cancelled.)

	REPLY and % are a bit slow, though fast enough for small mailing lists.
The slowest part may well be loading them in with EXECUTE!  If you use REPLY
frequently, but don't want to wait for it to be loaded in every time you execute
your personal EINIT file for something else, you may want to create a macro
(say, R) that EXECUTEs this page of EINIT[1,3] and then does
<control>#<control>ZREPLY<cr>.  With a little more hackery you could rig the R
macro to suppress the EXECUTE command on later calls -- e.g., have R invoke R1
to do the EXECUTE, and then replace R1 with some sort of "no-op".

	REPLY and % leave most modes, such as STOPHOW and TERSE, unchanged.  The
parenthesis characters for the "(" and ")" commands are changed (if necessary)
to be the default of "real" parentheses.  The search-stop-line (SSLINE) value is
cleared, and the defaults for the search/substitute commands are changed.  If it
was necessary to create a temporary distribution-list file, that file is left at
the bottom of the file stack.  Various macro names are used for numeric values
and other temporary storage, and the % macro is of course overridden.  The
undelete buffer size is unchanged; the undelete buffer is left holding the reply
subject and message text, such that an UNDELETE command retrieves them.
⊗⊃

αXDEFINE REPLY⊗↔
	αZRENTRY⊗↔			⊗; do our entry stuff (save modes, etc.)
	αXSET REPLW=WFLAG.⊗↔		⊗; remember whether W flag was on
	αZREPL0⊗↔			⊗; make sure blank line and no attach buffer
	αβ#αZREPL1⊗↔			⊗; put arg into REPARG for use by submacros
	αXPAREN⊗↔			⊗; make sure paren chars are "(" and ")"
	αZRPMAIN⊗↔			⊗; call main macro (this additional level
	αZEXIT2⊗↔			⊗; of nest makes aborting less noisy)
αβ⊗↓

αXDEFINE RENTRY⊗↔			⊗; does entry stuff for REPLY and REPSND
	⊗≠αZENTRYX⊗↔			⊗; leave line-editor (if in), save modes
	α-αXUNDELETE⊗↔			⊗; speed things up a little more
	αXSET REPLJC=CMAR.⊗↔αXSET REPLJL=LMAR.⊗↔αXSET REPLJR=RMAR.⊗↔	⊗; JFILL info
	αXSET REPLBK=BRKCOL.⊗↔αXSET REPDNT=INDENT.⊗↔	⊗; BREAK and INDENT values (latter faked)
αβ⊗↓

αXDEFINE REXIT1⊗↔			⊗; first stage of exit stuff (2nd is EXIT2)
	αZEXIT1⊗↔
	αXATTACH REPLJC⊗↔		⊗; get a line to work with
	αXJFILL REPLJC,REPLJL,REPLJR⊗↔	⊗; restore justification parameters
	αXINDENT REPDNT⊗↔		⊗; restore indentation default
	αXBREAK REPLBK⊗↔		⊗; restore default break column
	αβKαXSSLINE⊗↔			⊗; discard junk line, clear search stop
αβ⊗↓

αXDEFINE RPMAIN⊗↔
	αZREPL2⊗↔			⊗; find sender
	αZREPL3⊗↔			⊗; find orig recipients if REPARG=+1 or >1
	αZREPL4⊗↔			⊗; find original cc names if REPARG > 1
	αZREPL5⊗↔			⊗; find subject
	αZREPL6⊗↔			⊗; put heading and preface on reply text
	αZREPL7⊗↔			⊗; set up macro % = REPSND
	αZREXIT1⊗↔
αβ⊗↓

αXDEFINE REPLXX⊗↔			⊗; error exit
	αZREXIT1⊗↔
	αXSET REPTMP=LINE.⊗↔
	αXSTOPZERO⊗↔			⊗; suppress error if no text to attach
	αXARGUMENT REPLIN⊗↔αLα∞αβ!αA	⊗; restore attach buffer (if any)
	αXSSLINE⊗↔
	αXARGUMENT REPTMP⊗↔αL		⊗; now, where were we?
	α-α1αXARGUMENT MDEPTH.⊗↔αXABORT⊗↔	⊗; abort all but top level
αβ⊗↓

αXDEFINE REPL0⊗↔
	α∞αLαXSET REPLIN=LINE.⊗↔	⊗; go to bottom of incore page, save line #
	α0αA				⊗; drop attach buffer, if any, as reply text
	⊗↑α0αXNONEMPTY⊗↔⊗↔β⊗↔		⊗; put in blank line if wasn't any
	αXADD REPLIN⊗↔
αβ⊗↓

αXDEFINE REPL1⊗↔
	αβ#αXSET REPARG⊗↔α2αXMULTIPLY REPARG⊗↔	⊗; map 1 → 2, +1 → 3, >1 → >3
	αZREPARG⊗↔α⊗→αXSET REPTMP=ASCII.⊗↔⊗≠	⊗; enter line editor, then abort
	α4α3αXIFEQ REPTMP⊗↔			⊗; was first char of REPARG a "+"?
	αXADD REPARG⊗↔				⊗; if so, incr doubled value
αβ⊗↓

αXDEFINE REPL2⊗↔
	αLαXEMPTY⊗↔α+α0αXSSLINE⊗↔	⊗; searches stop before first blank line
	αZREPL2A⊗↔			⊗; look for right line in header
	αZRFC733⊗↔			⊗; parse RFC733 format, flush comments, etc.
	αXARGUMENT REPLIN⊗↔αLαE		⊗; take copy of line down to bottom
	αXADD REPLIN⊗↔			⊗; old attach buffer now further down
	⊗↔α1αβ⊗↔,αβUαXJOIN⊗↔		⊗; put comma on the end
	α1αXSIN⊗↔			⊗; remove tabs (exist only if "∂" line)
	αF,αβ\ ,⊗↔αXBREAK SRCHAR.⊗↔	⊗; break ahead of first comma
	⊗↔αβD⊗↑				⊗; flush stuff from comma to end
	α1αZREPNAM⊗↔			⊗; parse what's left to form a name
	α1αβ⊗↔⊗αI[In reply to message⊗α⊗β3⊗αXIFLE REPARG⊗⊗↔⊗αI from α⊗↔
	α2αXREDEFINE REPFRM⊗↔αβD	⊗; save id of sender for "in reply to" text
	αIReplying-To: α⊗↔		⊗; add our special field name
	αXSET REPLN2=LINE.⊗↔		⊗; remember this position for REPLST
αβ⊗↓

αXDEFINE REPL2A⊗↔
	αXSTOPZERO⊗↔αLαF⊗↓≡⊗↔Reply-To:⊗↓⊗↔⊗↔αXSET RPRPTO⊗↔	⊗; flag name found on Reply-To line
	αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔	⊗; exit if found!
	αXSTOPZERO⊗↔⊗↑αF⊗↓≡⊗↔From:⊗↓⊗↔⊗↔α0αXSET RPRPTO⊗↔
	αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔
	⊗↑α1α5αXIFNE ASCII.⊗↔		⊗; see if top line starts with "∂"
	αXSAY Sorry -- Can't find sender's name anywhere in header.⊗↔
	αZREPLXX⊗↔			⊗; abort
αβ⊗↓

αXDEFINE REPL3⊗↔
	α3αXIFLE REPARG⊗↔		⊗; do "also-to"s only if arg was +1 or >1
	αXSET RPLSTF←REPL3F⊗↔αXSET RPLSTI←REPL3I⊗↔	⊗; set up things for REPLST
	α1αZREPLST⊗↔αXIFEQ REPTOP⊗↔	⊗; REPTOP=1 iff no "to"s found
	αβXSAY Warning -- Unable to find any "To" lines.⊗↔
αβ⊗↓

αXDEFINE REPL3F⊗↔
	αF⊗↓≡⊗↔To:⊗↓⊗↔
αβ⊗↓

αXDEFINE REPL3I⊗↔
	αIAlso-to: α⊗↔
αβ⊗↓

αXDEFINE REPL4⊗↔
	α4αXIFLE REPARG⊗↔		⊗; send to cc's only if arg was >1
	αXSET RPLSTF←REPL4F⊗↔αXSET RPLSTI←REPL4I⊗↔	⊗; set up things for REPLST
	α1αZREPLST⊗↔αXSET RPLSTF←REPL4G⊗↔	⊗; find "cc"s, set up for "remailed-to"s
	αXARGUMENT REPTOP⊗↔αZREPLST⊗↔αXIFEQ REPTOP⊗↔	⊗; REPTOP=1 iff neither found
	αβXSAY Warning -- Unable to find any "CC" lines.⊗↔
αβ⊗↓

αXDEFINE REPL4F⊗↔
	αF⊗↓≡⊗↔cc:⊗↓⊗↔
αβ⊗↓

αXDEFINE REPL4G⊗↔
	αF⊗↓≡⊗↔Remailed-To:⊗↓⊗↔
αβ⊗↓

αXDEFINE REPL4I⊗↔
	αIReply-cc: α⊗↔
αβ⊗↓

αXDEFINE REPL5⊗↔
	αXARGUMENT REPLN2⊗↔αXSSLINE⊗↔	⊗; don't search reply text
	αXSTOPZERO⊗↔⊗↔αLαF⊗↓≡⊗↔Subject:⊗↓⊗↔αXSTOPONE⊗↔	⊗; look for RFC733 subject line
	αXARGUMENT NFOUND.⊗↔αXCASE REPL5A REPL5B⊗↔
	αXARGUMENT REPLIN⊗↔αLαE		⊗; take attached reply-subject down to our header
	αXADD REPLIN⊗↔			⊗; note movement downward of reply text
	α+αXSSLINE⊗↔αFReply-Subject: re: re:αβ\Reply-Subject: re:⊗↔	⊗; eschew redundant tautology
αβ⊗↓

αXDEFINE REPL5A⊗↔
	αZREP5A0⊗↔				⊗; try for "∂" line (aborts us if succeeds)
	α1αβ⊗↔Reply-Subject: reply to messageαβA	⊗; couldn't find subject at all
αβ⊗↓

αXDEFINE REP5A0⊗↔
	α1α5αXIFEQ ASCII.⊗↔			⊗; check top line for "∂"
	α+αXSSLINE⊗↔α2αF⊗=⊗↔			⊗; does line include two tabs?
	α+α1αXARGUMENT SRCHAR.⊗↔αXIFLT CHARS.⊗↔	⊗; and does second tab have stuff after it?
	αCαEαXSSLINE⊗↔αF⊗=αβ\  αβ2⊗↔		⊗; a winner!  copy it; tabs -> dbl-space
	αXBREAK SRCHAR.⊗↔			⊗; break between second pair of spaces
	αβDα1αβ⊗↔Reply-Subject: re:α⊗↔αXJOIN⊗↔	⊗; create our header line
	αAαXTIN⊗↔αXSIN⊗↔			⊗; flush trailing blanks
	α2αXABORT⊗↔				⊗; abort REPL5A
αβ⊗↓

αXDEFINE REPL5B⊗↔
	⊗↔αCαEαFSubjectαβ\Reply-Subject: re⊗↔	⊗; copy RFC733 subject line and make it ours
	αA					⊗; pick it up
αβ⊗↓

αXDEFINE REPL6⊗↔
	αXARGUMENT REPLIN⊗↔αLα3αβ⊗↔	⊗; go to top of reply text and add header
	⊗↔Reply-Text:⊗↔
	α3αXADD REPLIN⊗↔		⊗; that moved text down three lines
	αZREPL6A⊗↔			⊗; see if we can find date/time
	αβD				⊗; delete junk line left by REP6A0 or REPL6A
	αXARGUMENT REPLN2⊗↔αLαJ		⊗; go to top of reply headers and jump them
	αXARGUMENT REPLIN⊗↔αL		⊗; move arrow to top of reply text
αβ⊗↓

αXDEFINE REPL6A⊗↔
	αLαXARGUMENT REPLN2⊗↔αXSSLINE⊗↔		⊗; don't search reply text
	αXSTOPZERO⊗↔αF⊗↓≡⊗↔Date:⊗↓⊗↔αXSTOPONE⊗↔	⊗; try to find RFC733 date line
	αXARGUMENT NFOUND.⊗↔αXCASE REP6A0 REP6A1⊗↔
	⊗; REP6A0 leaves us with attached date/time if found, else in line editor on junk line
	⊗; REP6A1 always gives us attached date/time unless RFC733 aborts everything
	⊗≠αXIFEQ ATTSIZ.⊗↔		⊗; if nothing, abort; no big loss, so no error msg
	αXARGUMENT REPLIN⊗↔αLαE		⊗; take it down to top of reply text
	⊗↔β⊗↔α2αXADD REPLIN⊗↔		⊗; separate it from reply text by blank line
	α-αCαE				⊗; create junk line for REPL6 to delete
αβ⊗↓

αXDEFINE REP6A0⊗↔
	αCαXJFILL 0,0,999⊗↔αE		⊗; copy line and flush tabs/multiple-spaces
	α1α5αXIFEQ ASCII.⊗↔		⊗; if top line is "∂", get its date/time
	α1α6αXIFLE COLS.⊗↔		⊗; line must have 16 cols if date/time there
	αXBREAK 16⊗↔⊗↔αβD⊗↑		⊗; flush rest of line
	αDαβ4αβ8αXIFLE ASCII.⊗↔αβ5αβ7αXIFGE ASCII.⊗↔	⊗; next char must be digit
	αS αβ9αXIFEQ CHAR.⊗↔		⊗; first "word" must be 9 chars ("dy-mon-yr")
	α αβ4αβ8αXIFLE ASCII.⊗↔αβ5αβ7αXIFGE ASCII.⊗↔	⊗; second "word" must start w/ digit
	αS αβ1αβ4αXIFEQ CHAR.⊗↔		⊗; second "word" must be 4 chars (time)
	α⊗→αZREPFRM⊗↔αI rcvd α1α2α β:αS -PT.]αβA
αβ⊗↓

αXDEFINE REP6A1⊗↔
	⊗↔α∞αZRFC733⊗↔			⊗; move to "date" line, parse it (∞ = arg, not rep cnt)
	αEα2αβ⊗↔ sent α⊗→αZREPFRM⊗↔α ⊗↔	⊗; prepare enclosing text
	.]αβA⊗↔αEα-α2αXJOIN⊗↔α1αXJFILL 0,0,999⊗↔	⊗; combine preface and date
	αXJOIN⊗↔αXSTOPZERO⊗↔α+αXSSLINE⊗↔αF..]αβ\.]αβ∞⊗↔αXSTOPONE⊗↔αA
αβ⊗↓

αXDEFINE REPL7⊗↔
	αXSET %=REPSND⊗↔		⊗; copy final-step macro to convenient name
	αXSAY  Type <control>% when ready to mail.   ⊗↔
αβ⊗↓

αXDEFINE RFC733⊗↔
	αZRFC1⊗↔			⊗; handle "∂" lines specially
	αCα∞αZRFC2⊗↔			⊗; copy first line and all continuations
	αEα+αXSSLINE⊗↔αXSTOPZERO⊗↔	⊗; prepare to muck around on the one line
	αF⊗=αβ\ αβ∞⊗↔			⊗; all tabs become spaces
	αXSTOPONE⊗↔⊗↑⊗↔αF:⊗↔		⊗; find colon at end of header field name
	αXBREAK SRCHAR.⊗↔		⊗; break line so colon starts second line
	αβDαF:αβ\⊗↔			⊗; flush header name and colon
		⊗⊂ now the tricky part: (1) flush parenthesised portions, which are
		comments, but watch out for nesting and for quoted strings (quotes
		inside parens are comments; parens in quotes are not!)  (2) change
		special chars <space>, <comma>, ":" and "@" in quotes to temporary
		chars that won't screw up later parsing.  main reason it's so tricky
		is we're not sure line fits in line editor. ⊗⊃
	β⊗↔α∞αZRFC3⊗↔			⊗; create "collecting" line; handle parens
	⊗↑αXJOIN⊗↔			⊗; done parsing comments
	β⊗↔α∞αZRFC4⊗↔			⊗; create new collecting line; handle quotes
	⊗↑αXJOIN⊗↔			⊗; done parsing quoted strings
	β⊗↔α#αZRFC5⊗↔			⊗; create new collecting line; handle colons
	⊗↑αXJOIN⊗↔			⊗; done parsing <comment>:<text>; format
	αXSTOPZEROα+αXSSLINE⊗↔αFεαβ\αβ∞⊗↔	⊗; flush all the "ε"s that got added
	αXSTOPONE⊗↔αA			⊗; pick up final version
αβ⊗↓

αXDEFINE RFC1⊗↔
	α1α5αXIFEQ ASCII.⊗↔		⊗; see if this is a "∂" line
	αCαEα⊗=⊗=α⊗→αS⊗=αRαK⊗↔αA	⊗; yes; copy it, flush subject field
	α2αXABORT⊗↔			⊗; abort RFC733
αβ⊗↓

αXDEFINE RFC2⊗↔
	α3α2αXIFEQ ASCII.⊗↔		⊗; if next line starts with space, add it
	α+αCαXJOIN⊗↔			⊗; to attach buffer and join with rest
αβ⊗↓

αXDEFINE RFC3⊗↔
	α+αXSSLINE⊗↔αF(αβ\ε(⊗↔		⊗; find "(", done if none
	αXBREAK SRCHAR.⊗↔		⊗; break ahead of "("; "ε" ensures SRCHAR≠0
	α+αXSSLINE⊗↔αXSTOPZERO⊗↔	⊗; prepare to search up to "("
	α∞αF"⊗↔αXSET REPTMP=NFOUND.⊗↔	⊗; get number of quotes ahead of "("
	αXSTOPONE⊗↔α2αXREMAINDER REPTMP⊗↔		⊗; odd or even?
	αXARGUMENT REPTMP⊗↔αXCASE RFC3A RFC3B⊗↔	⊗; call subcase
αβ⊗↓

αXDEFINE RFC3A⊗↔
	⊗↔αAαXSET REPTMP=LINE.⊗↔α∞αL	⊗; take line to bottom of page
	α1αXBREAK 80⊗↔αE		⊗; break into bite-size chunks
	αXSET REPTM2=LINE.⊗↔		⊗; remember where first 80-char chunk is
	αZRFC3A0⊗↔			⊗; look for ")", return only if NOT found
	αXSAY Sorry -- Couldn't find matching close parenthesis in above header line.⊗↔
	αXARGUMENT REPTM2⊗↔αLα∞αβ!αβD	⊗; failed; clean up (∞! stops at pagemark)
	αXARGUMENT REPTMP⊗↔αLα-α2αβD
	αZREPLXX⊗↔
αβ⊗↓

αXDEFINE RFC3A0⊗↔
	α)				⊗; find matching ")", abort if missing
	αL⊗↔αDα⊗↔			⊗; kill left to beginning of line, kill ")"
	αXARGUMENT LINE.⊗↔αXSUBTRACT REPTM2⊗↔	⊗; compute -# lines from "(" to here
	αXARGUMENT REPTM2⊗↔αβD		⊗; delete all those lines
	α∞αβ!αAα∞αXJOIN⊗↔		⊗; pick up what's left (∞! stops at pagemark)
	αXARGUMENT REPTMP⊗↔αLαE		⊗; put it back where we were
	α-α2αXJOIN⊗↔			⊗; join stuff left of "(" on collection line
	⊗↔				⊗; get back to working line
	α2αXABORT⊗↔			⊗; abort RFC3A
αβ⊗↓

αXDEFINE RFC3B⊗↔
	⊗↔α+αXSSLINE⊗↔			⊗; odd number of quotes, search for one more
	αXSTOPZERO⊗↔αF"αβ\"ε⊗↔αXSTOPONE⊗↔	⊗; handle failing search specially
	α1αXARGUMENT NSUBST.⊗↔αZRFC3B0⊗↔	⊗; REP3CY aborts if arg=1 (NSUBST=0)
	αXBREAK SRCHAR.⊗↔		⊗; break between " and ε
	α2⊗↑α3αXJOIN⊗↔			⊗; join through quote on collection line
	⊗↔				⊗; down to working line again
αβ⊗↓

αXDEFINE RFC3B0⊗↔
	αXSET REPTMP⊗↔α#αXIFEQ REPTMP⊗↔	⊗; abort if arg = 1
	αXSAY Sorry -- Couldn't find matching quote in above header line.⊗↔
	α2⊗↑α3αβD
	αZREPLXX⊗↔
αβ⊗↓

αXDEFINE RFC4⊗↔
	α+αXSSLINE⊗↔αF"αβ\ε"⊗↔		⊗; find quote, done if none
	αXBREAK SRCHAR.⊗↔		⊗; break between quote and newly added "ε"
	αXSTOPZERO⊗↔⊗↔α2αF"αβ\"ε⊗↔αXSTOPONE⊗↔	⊗; find close quote (SSLINE still okay)
	α1αXARGUMENT NSUBST.⊗↔αZRFC3B0⊗↔	⊗; abort if couldn't find it
	αXBREAK SRCHAR.⊗↔		⊗; break between close quote and "ε"
	α+αXSSLINE⊗↔αXSTOPZERO⊗↔	⊗; prepare to change special chars (if any)
	⊗↑⊗↔αF αβ\∧αβ∞⊗↔		⊗; space becomes logical-and
	⊗↑⊗↔αF,αβ\∨αβ∞⊗↔		⊗; comma becomes logical-or
	⊗↑⊗↔αF:αβ\∃αβ∞⊗↔		⊗; colon becomes there-exists
	⊗↑⊗↔αF@αβ\∀αβ∞⊗↔		⊗; atsign becomes forall
	αXSTOPONE⊗↔
	α2⊗↑α3αXJOIN⊗↔			⊗; join thru close-quote on collecting line
	⊗↔				⊗; back to the working line
αβ⊗↓

αXDEFINE RFC5⊗↔
	α#αXIFLE CHARS.⊗↔α∞αZRFC5A⊗↔	⊗; if arg=∞, parsing date; let colons be
αβ⊗↓

αXDEFINE RFC5A⊗↔
	α+αXSSLINE⊗↔αF:αβ\εε⊗↔		⊗; find colon, done if none, flush if there
	αXBREAK SRCHAR.⊗↔		⊗; break between the two newly-added "ε"s
	αβ⊗↔,α⊗↔αXJOIN⊗↔α+αXSSLINE⊗↔	⊗; make sure at least one comma before colon
	αXSTOPZERO⊗↔α∞αF,⊗↔		⊗; find last comma (if any) before colon
	αXSTOPONE⊗↔αXARGUMENT NFOUND.⊗↔αF,αβ\,ε⊗↔
	αXBREAK SRCHAR.⊗↔⊗↑⊗↔αF,αβ\⊗↔	⊗; flush extra comma from front
	⊗↑αXJOIN⊗↔⊗↔αβD			⊗; discard text between comma and incl colon
	α+αXSSLINE⊗↔αF;αβ\εε⊗↔		⊗; find matching semi (need not be present)
	αXBREAK SRCHAR.⊗↔		⊗; break ahead of where semi was
	⊗↑αXJOIN⊗↔			⊗; put intervening text on collecting line
	⊗↔				⊗; back to the working line
αβ⊗↓

αXDEFINE REPNAM⊗↔
	⊗; if arg (rep cnt) > 1, allow any length local name and also quoted local names
	⊗; if arg = 1, have REPNM6 save "@<host>" string for later use as default
	α#αZREPNM0⊗↔			⊗; assume RFC733 was called; parse a name
	α#αZREPNM6⊗↔			⊗; save hostname if #=1, else apply default
	α+αXSSLINE⊗↔αZREPNM8⊗↔		⊗; flush "@SAIL" and strip quotes if local
	αXSTOPZERO⊗↔⊗↑⊗↔αF∧αβ\ αβ∞⊗↔	⊗; change back special chars
	⊗↑⊗↔αF∨αβ\,αβ∞⊗↔
	⊗↑⊗↔αF∃αβ\:αβ∞⊗↔
	⊗↑⊗↔αF≡∀αβ\@αβ∞⊗↔
	αXSTOPONE⊗↔
αβ⊗↓

αXDEFINE REPNM0⊗↔
	⊗; REPNM1-5,7 abort REPNM0 if successful, else leave junk line (except ##4-5,7)
	αZREPNM1⊗↔αβD⊗↑			⊗; look for "<NAME at SITE>" or "<NAME @ SITE>"
	αZREPNM2⊗↔αβD⊗↑			⊗; look for "NAME at SITE"
	αZREPNM3⊗↔αβD⊗↑			⊗; look for "NAME @ SITE"
	αZREPNM4⊗↔			⊗; try first alph string after space/tab
	α-αCαEα#αZREPNM6⊗↔αβD		⊗; if #=1, find out if Remailed-from exists
	α#αXARGUMENT RPDFLT⊗↔αZREPNM5⊗↔	⊗; try first string if alph or quoted & arg>1 or def host known
	α#αZREPNM7⊗↔			⊗; if name was on Reply-To, don't argue!
	αXSAY Sorry -- Can't find a name in the above line.⊗↔
	αZREPLXX⊗↔			⊗; abort
αβ⊗↓

αXDEFINE REPNM1⊗↔
	αCαEα+αXSSLINE⊗↔αF<αβ\ε<⊗↔	⊗; look for "<", delete portion to left
	αXBREAK SRCHAR.⊗↔αβDαF<αβ\⊗↔	⊗; also delete the "<"; SSLINE still okay
	αF>αβ\>ε⊗↔			⊗; look for ">", delete portion to right
	αXBREAK SRCHAR.⊗↔⊗↔αβD⊗↑αF>αβ\⊗↔
	αXSTOPZERO⊗↔⊗↑⊗↔α+αXSSLINE⊗↔	⊗; if " at " appears, replace with "@"
	αF at αβ\@⊗↔αXSTOPONE⊗↔
	αZREPNMX⊗↔			⊗; parse stuff around "@"; return if failed
αβ⊗↓

αXDEFINE REPNM2⊗↔
	αCαEα+αXSSLINE⊗↔αF at αβ\@⊗↔	⊗; look for " at " and replace with "@"
	αZREPNMX⊗↔			⊗; parse stuff around "@"; return if failed
αβ⊗↓

αXDEFINE REPNM3⊗↔
	αCαEαZREPNMX⊗↔			⊗; look for "@" and parse it if found
αβ⊗↓

αXDEFINE REPNMX⊗↔		⊗; parse name and site from around "@"
	αXINDENT -9999⊗↔α1αXTIN⊗↔α1αXSIN⊗↔	⊗; strip leading/trailing blanks
	⊗↑⊗↔α+αXSSLINE⊗↔		⊗; make sure search will work right
	αF@⊗↔αXIFLE SRCHAR.⊗↔		⊗; make sure SOMETHING to left of "@"!
	α1αXARGUMENT SRCHAR.⊗↔αXIFLT CHARS.⊗↔	⊗; and something to right
	αXBREAK SRCHAR.⊗↔		⊗; get name by itself
	αAαXJFILL 0,0,1⊗↔		⊗; break into separate words
	α-αAα+αCαβK			⊗; save just the last word
	αXBREAK 1⊗↔			⊗; separate "@" (we know there's more)
	⊗↔αAαXJFILL⊗↔			⊗; get site by itself (first word after "@")
	αXSET REPTMP⊗↔αXARGUMENT ATTSIZ.⊗↔αXSUBTRACT REPTMP⊗↔
	αXARGUMENT REPTMP⊗↔αCα0αA	⊗; discard all but first, then put it down
	⊗; (might have done α0αC to drop it, hence α0αA (= nop) instead of αE)
	α2⊗↑α3αXJOIN⊗↔			⊗; put it together again
	αXSSLINE⊗↔αF@⊗↔			⊗; get SRCHAR pointing to "@" for REPNMQ
	α-αβD				⊗; delete original line
	α3αXABORT⊗↔			⊗; abort REPNM0
αβ⊗↓

αXDEFINE REPNM4⊗↔
	αCαXJFILL 0,0,1⊗↔		⊗; break into words
	αXSET REPTMP=ATTSIZ.⊗↔		⊗; save number of words
	αEα∞αZRPNM4A⊗↔			⊗; look at each line for SAIL prog name
αβ⊗↓

αXDEFINE RPNM4A⊗↔
	αZRPNM4B⊗↔			⊗; check one line, return if failed
	α⊗↔αβDαXSUBTRACT REPTMP⊗↔	⊗; keep REPTMP as number of lines left
	αXIFLE REPTMP⊗↔			⊗; give up if REPTMP hits (or is set to) 0
αβ⊗↓

αXDEFINE RPNM4B⊗↔
	α6α5αXIFLE ASCII.⊗↔αXSET REPTM2=ASCII.⊗↔	⊗; look for first line that
	α3α2αXREMAINDER REPTM2⊗↔αXIFLE REPTM2⊗↔		⊗; starts with alphabetic
	α2α6αXIFGE REPTM2⊗↔
	⊗↔α-α1αXARGUMENT REPTMP⊗↔αβD	⊗; got it; ignore remaining lines
	⊗↑αXSET REPTMP⊗↔		⊗; set REPTMP to abort RPNM4A if we fail
	αXIFLT CHARS.⊗↔α4αXIFGT CHARS.⊗↔	⊗; must be either 2 or 3 chars
	α αβ6αβ5αXIFLE ASCII.⊗↔αXSET REPTM2=ASCII.⊗↔	⊗; second char alpha?
	αβ3αβ2αXREMAINDER REPTM2⊗↔αXIFLE REPTM2⊗↔αβ2αβ6αXIFGE REPTM2⊗↔
	α⊗=α⊗↑αβ6αβ5αXIFLE ASCII.⊗↔αXSET REPTM2=ASCII.⊗↔	⊗; last char alpha?
	αβ3αβ2αXREMAINDER REPTM2⊗↔αXIFLE REPTM2⊗↔αβ2αβ6αXIFGE REPTM2⊗↔
	α⊗↔α-αβDα4αXABORT⊗↔		⊗; a winner! abort all the way up to REPNM0
αβ⊗↓

αXDEFINE REPNM5⊗↔
	⊗; permit this case only on "to" or "cc" or if def host known due to "remailed-from" line
	α#αXSET REPTMP⊗↔α2αXIFLT REPTMP⊗↔
	α-αCαXJFILL 0,0,1⊗↔		⊗; break line into words
	αXSET REPTMP=ATTSIZ.⊗↔		⊗; save number of words
	αE⊗↔α-α1αXARGUMENT REPTMP⊗↔αβD	⊗; delete all but the first word
	⊗↑αZRPNM5A⊗↔			⊗; check for quoted string (e.g., "#<file>")
	α⊗↔αZRPNM5B⊗↔			⊗; check for first-char = alph
	αβD				⊗; no luck; flush line, let REPNM0 bitch
αβ⊗↓

αXDEFINE RPNM5A⊗↔
	α3α4αXIFEQ ASCII.⊗↔		⊗; make sure line starts with quote
	α9α9αXIFGE CHARS.⊗↔		⊗; local quoted names (#file, @file) always fairly short
	α⊗=α⊗↑αβ3αβ4αXIFEQ ASCII.⊗↔	⊗; make sure line ends with quote
	α⊗↔α-αβDα3αXABORT⊗↔		⊗; success! abort ourselves, REPNM5, and REPNM0
αβ⊗↓

αXDEFINE RPNM5B⊗↔
	α6α5αXIFLE ASCII.⊗↔αXSET REPTM2=ASCII.⊗↔	⊗; check for alph as in RPNM4B
	α3α2αXREMAINDER REPTM2⊗↔αXIFLE REPTM2⊗↔α2α6αXIFGE REPTM2⊗↔	⊗; allow lowercase
	α-αβDα3αXABORT⊗↔		⊗; alph it is, assume it's a forwarded name @SAIL
αβ⊗↓

αXDEFINE REPNM6⊗↔
	⊗; if arg = 1, look for "@" and save hostname for later use as default
	⊗; if arg > 1, look for "@" and if not found append default
	α+αXSSLINE⊗↔α#αXSET REPTMP⊗↔α2αXMINIMUM REPTMP⊗↔
	α-α1αXARGUMENT REPTMP⊗↔αXCASE RPNM6A RPNM6B⊗↔
αβ⊗↓

αXDEFINE RPNM6A⊗↔
	αXSET RPDFLT⊗↔			⊗; flag that no default known yet
	αZRPNM6C⊗↔			⊗; look for one on this line
	αXSET REPTMP=LINE.⊗↔		⊗; no luck, look for host Remailed-from
	αCαEαLαXEMPTY⊗↔α+α0αXSSLINE⊗↔	⊗; create junk line, restrict search to header
	αLαXARGUMENT REPTMP⊗↔αZRPNM6D⊗↔	⊗; RPNM6D might replace junk with new junk
	αXARGUMENT REPTMP⊗↔αLαβD	⊗; whether or not that worked, we're through
	αZRPNM6B⊗↔			⊗; except we should apply Remailed-from host to this line, too!
αβ⊗↓

αXDEFINE RPNM6B⊗↔
	αXIFNE RPDFLT⊗↔			⊗; abort unless we know sender's host
	α+αXSSLINE⊗↔αXSTOPZERO⊗↔⊗↔⊗↑αF@⊗↔	⊗; look for "@" on this line
	αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔	⊗; exit if found
	⊗↔αXATTACH RPHOST⊗↔αE⊗↑αXJOIN⊗↔	⊗; else append default host text
αβ⊗↓

αXDEFINE RPNM6C⊗↔
	α+αXSSLINE⊗↔⊗↔⊗↑αF@⊗↔		⊗; look for "@", abort if none
	αXBREAK SRCHAR.⊗↔⊗↔		⊗; break line ahead of "@"
	α1αXREDEFINE RPHOST⊗↔⊗↑αXJOIN⊗↔	⊗; save "@<host>" in handy macro, rejoin
	αXADD RPDFLT⊗↔			⊗; flag that default host is now known
	α2αXABORT⊗↔			⊗; abort RPNM6A (don't look for Remailed-from)
αβ⊗↓

αXDEFINE RPNM6D⊗↔
	αF⊗↓≡⊗↔Remailed-From:⊗↓⊗↔⊗↔	⊗; look for first remailer, abort if none
	αZRFC733⊗↔α#αL⊗↔αEα-αβD		⊗; parse RFC format, replace junk line with this
	α2αZREPNM0⊗↔			⊗; parse for name, don't restore spec chars
	α#αXSET REPTMP⊗↔		⊗; REPTMP used by parsing macros
	αZRPNM6C⊗↔			⊗; see if it has "@host" for us
αβ⊗↓

αXDEFINE REPNM7⊗↔
	α#αXIFEQ RPRPTO⊗↔		⊗; looking for sender's name in Reply-To field?
	⊗↑αXINDENT -9999⊗↔α1αXTIN⊗↔α1αXSIN⊗↔
	α2αXABORT⊗↔			⊗; well, look no further!
αβ⊗↓

αXDEFINE REPNM8⊗↔
	αXSTOPZERO⊗↔			⊗; flush local address (BEFORE restoring "@"s!)
	⊗↑⊗↔αF@SAILαβ\⊗↔⊗↑⊗↔αF@SU-AIαβ\⊗↔
	⊗↑⊗↔αF@⊗↔αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔	⊗; that's it unless no "@" now
	α3αXIFLE CHARS.⊗↔		⊗; first off, enough chars for quoted string?
	α3α4αXIFEQ ASCII.⊗↔		⊗; see if local name starts with quote
	αXSTOPZERO⊗↔⊗↑⊗↔α∞αF"⊗↔		⊗; yep, look for too many of them
	αXARGUMENT NFOUND.⊗↔αβ*		⊗; now look for last on this line (at least 1!)
	αXSTOPONE⊗↔α+α1αXARGUMENT SRCHAR.⊗↔αXIFEQ CHARS.⊗↔	⊗; is last quote the last char?
	αXBREAK SRCHAR.⊗↔αXBREAK 1⊗↔	⊗; everything checks, discard quotes
	αβD⊗↔αβD⊗↑α+αXSSLINE⊗↔
αβ⊗↓

αXDEFINE REPLST⊗↔
	αXSET REPTOP⊗↔			⊗; line from which to search, start at top
	α∞αZRPLST1⊗↔			⊗; process all the "to" or "cc" lines
	α#αXMAXIMUM REPTOP⊗↔		⊗; remember furthest we ever found a hit
αβ⊗↓

αXDEFINE RPLST1⊗↔
	αXARGUMENT REPTOP⊗↔αL⊗↔⊗↑	⊗; go to position of last line found
	αXARGUMENT REPLN2⊗↔αXSSLINE⊗↔	⊗; don't search original attached text
	αZRPLSTF⊗↔			⊗; look for appropriate header line
	αXIFEQ NFOUND.⊗↔		⊗; if none found, we're done
	⊗↔αXSET REPTOP=LINE.⊗↔		⊗; move down to actual line, save position
	αZRFC733⊗↔			⊗; pick up line, flush comments, etc.
	αXARGUMENT REPLIN⊗↔αLαE		⊗; take it down to bottom
	αXADD REPLIN⊗↔			⊗; old attach buffer now further down
	⊗↔α1αβ⊗↔,αβUαXJOIN⊗↔		⊗; put comma on the end
	α∞αZRPLST2⊗↔			⊗; parse as many names as there are commas
	αβDαXSUBTRACT REPLIN⊗↔		⊗; delete whatever's left (probably null)
αβ⊗↓

αXDEFINE RPLST2⊗↔
	α+αXSSLINE⊗↔αF,αβ\  ⊗↔αXBREAK SRCHAR.⊗↔	⊗; break ahead of first comma
	αZRPLS2A⊗↔			⊗; process stuff ahead of comma
	αβD				⊗; delete either blank line or junk line
αβ⊗↓

αXDEFINE RPLS2A⊗↔
	α1αXTIN⊗↔α1αXSIN⊗↔		⊗; get rid of trailing spaces
	αXIFLE CHARS.⊗↔			⊗; see if line had nothing but spaces
	αXADD REPLIN⊗↔			⊗; real text; account for BREAK in RPLST2
	α2αZREPNAM⊗↔			⊗; parse pre-comma text to form a name (2=arg, not rep cnt)
	αZRPLSTI⊗↔			⊗; add our special field name
	αCαE				⊗; make a copy for RPLST2 to delete
αβ⊗↓

αXDEFINE REPSND⊗↔
	αZRENTRY⊗↔
	αZREPSN0⊗↔			⊗; extra nesting level for quieter aborting
	αZEXIT2⊗↔
αβ⊗↓

αXDEFINE REPLX2⊗↔			⊗; error exit for REPSND
	αXSSLINE⊗↔αZREXIT1⊗↔
	α-α1αXARGUMENT MDEPTH.⊗↔αXABORT⊗↔
αβ⊗↓

αXDEFINE REPSN0⊗↔
	αZREPSN1⊗↔			⊗; find reply header; adjust REPLN2 & REPLIN if necessary
	αZREPSN2⊗↔			⊗; convert lines REPLN2 thru REPLIN-1 into mailing list
	αZREPSN3⊗↔			⊗; send the mail and clean up (leave reply text in undelete buf)
αβ⊗↓

αXDEFINE REPSN1⊗↔
	αZRPSN1A⊗↔			⊗; find "replying-to" line
	⊗↔αXSET REPLN2=LINE.⊗↔		⊗; remember its current position
	αZRPSN1B⊗↔			⊗; find "reply-text" line
	⊗↔αXSET REPLIN=LINE.⊗↔		⊗; remember it, too
	αXARGUMENT REPLN2⊗↔αL		⊗; go to top of reply header
	αXSET REPTMP=REPLIN⊗↔α1αXARGUMENT REPLN2⊗↔αXSUBTRACT REPTMP⊗↔
	αXIFLE REPTMP⊗↔			⊗; any lines between replying-to and reply-text?
	αXARGUMENT REPTMP⊗↔αZRPSN1C⊗↔	⊗; yes, check them for validity
	αXARGUMENT REPLIN⊗↔αL		⊗; go to reply-text line
	αXSTOPZERO⊗↔αXNONEMPTY⊗↔	⊗; see if there's any text line after it
	αXSTOPONE⊗↔αXARGUMENT LINE.⊗↔αXIFEQ REPLIN⊗↔	⊗; return if there is
	αβXSAY⊗↔αβXSAY Sorry -- No text found after "Reply-Text" line.⊗↔
	αZREPLX2⊗↔
αβ⊗↓

αXDEFINE RPSN1A⊗↔
	αXARGUMENT REPLN2⊗↔αL		⊗; go to approx loc of "replying-to" line
	α+αXSSLINE⊗↔⊗↑			⊗; first search just the one line
	αXSTOPZERO⊗↔αF⊗↓≡⊗↔Replying-To:⊗↓⊗↔αXSTOPONE⊗↔
	αXIFNE NFOUND.⊗↔		⊗; exit if we found it
	αXSTOPZERO⊗↔⊗↔αXEMPTY⊗↔	⊗; try searching whole paragraph
	α+α0αXSSLINE⊗↔α-αXEMPTY⊗↔αβ*
	αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔	⊗; again exit if found
	αLαXARGUMENT LINES.⊗↔αXSSLINE⊗↔	⊗; search whole page
	αXSTOPZERO⊗↔αβ*αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔
	αβXSAY⊗↔αβXSAY Sorry -- Can't find the "Replying-To" line.⊗↔
	αZREPLX2⊗↔
αβ⊗↓

αXDEFINE RPSN1B⊗↔
	α!⊗↔α+α2αXSSLINE⊗↔		⊗; go to end of "replying-to" graf; check next line
	αXSTOPZERO⊗↔αF⊗↓≡⊗↔Reply-Text:≡⊗↔⊗↓⊗↔αXSTOPONE⊗↔
	αXIFNE NFOUND.⊗↔		⊗; exit if found header
	αXARGUMENT REPLN2⊗↔αL		⊗; else try from "replying-to" to end
	αXARGUMENT LINES.⊗↔αXSSLINE⊗↔αXSTOPZERO⊗↔αβ*αXSTOPONE⊗↔αXIFNE NFOUND.⊗↔
	αβXSAY⊗↔αβXSAY Sorry -- Can't find the "Reply-Text" line.⊗↔
	αZREPLX2⊗↔
αβ⊗↓

αXDEFINE RPSN1C⊗↔
	αZRPSN1D⊗↔			⊗; want to be able to abort one iteration at a time
αβ⊗↓

αXDEFINE RPSN1D⊗↔
	⊗↔α+αXSSLINE⊗↔⊗↑		⊗; go to next line and restrict searches to it
	αXSTOPZERO⊗↔αXSET REPTMP⊗↔	⊗; flag saying whether any search won
	αF⊗↓≡⊗↔Also-To:⊗↓⊗↔αXARGUMENT NFOUND.⊗↔αXADD REPTMP⊗↔
	αF⊗↓≡⊗↔Reply-cc:⊗↓⊗↔αXARGUMENT NFOUND.⊗↔αXADD REPTMP⊗↔
	αF⊗↓≡⊗↔Reply-Subject:⊗↓⊗↔αXARGUMENT NFOUND.⊗↔αXADD REPTMP⊗↔
	⊗↔αXSTOPONE⊗↔αXIFEQ REPTMP⊗↔	⊗; abort if any of the searches won
	α0αXNONEMPTY⊗↔			⊗; empty lines are also legal in the header
	αβXSAY⊗↔αβXSAY Sorry -- This line doesn't seem to belong in the reply header.⊗↔
	αZREPLX2⊗↔
αβ⊗↓

αXDEFINE REPSN2⊗↔
	αXSET REPTMP⊗↔			⊗; number of "name" lines initially = 1 (replying-to)
	αXARGUMENT REPLIN⊗↔αXSSLINE⊗↔	⊗; stop searches at reply text
	αXSTOPZERO⊗↔αF⊗↓≡⊗↔Reply-cc:⊗↓⊗↔	⊗; set up search string
	α1αXARGUMENT REPLN2⊗↔αL		⊗; collect all the cc lines (if any)
	αXSTOPONE⊗↔α∞αZRPSN2A⊗↔
	αXARGUMENT ATTSIZ.⊗↔αXADD REPTMP⊗↔	⊗; remember total # of names
	α1αXARGUMENT REPLN2⊗↔αLα0αA	⊗; drop them just below replying-to
	αZRPSN2B⊗↔			⊗; add "/cc" to first one if any
	αXSTOPZERO⊗↔αF⊗↓≡⊗↔Also-To:⊗↓⊗↔	⊗; do it again for also-to's
	α1αXARGUMENT REPLN2⊗↔αLαXSTOPONE⊗↔α∞αZRPSN2A⊗↔
	αXARGUMENT ATTSIZ.⊗↔αXADD REPTMP⊗↔
	α1αXARGUMENT REPLN2⊗↔αLα0αA	⊗; drop them between replying-to and reply-cc's
	⊗↑αXARGUMENT REPTMP⊗↔αZRPSN2C⊗↔	⊗; convert field name on each line to comma
	αXARGUMENT REPLN2⊗↔αLαXARGUMENT REPTMP⊗↔αXJOIN⊗↔	⊗; make one big line
	α-α1αXARGUMENT REPTMP⊗↔αXSUBTRACT REPLIN⊗↔	⊗; reply-text thereby moved
	αF,αβ\MAIL ⊗↔			⊗; so much for the name list
	αZRPSN2D⊗↔			⊗; take care of reply-subject (if any)
	αXARGUMENT REPLIN⊗↔αLαXNONEMPTY⊗↔	⊗; go to top of reply text (probably subject)
	αXSET REPTMP=REPLN2⊗↔α-α1αXARGUMENT LINE.⊗↔αXSUBTRACT REPTMP⊗↔
	αXARGUMENT REPTMP⊗↔αβD		⊗; delete all lines between MAIL command and top of text
	⊗↑				⊗; leave us sitting on MAIL command line
αβ⊗↓

αXDEFINE RPSN2A⊗↔
	⊗↑αβ*⊗↔α+αA
αβ⊗↓

αXDEFINE RPSN2B⊗↔
	αXIFLT REPTMP⊗↔			⊗; were there any attached reply-cc lines?
	⊗↔α1αβ⊗↔/ccαβUαXJOIN⊗↔		⊗; yes; add "/cc" to the first one
αβ⊗↓

αXDEFINE RPSN2C⊗↔
	αF:αβ\ ⊗↔αXBREAK SRCHAR.⊗↔αβD	⊗; break off and discard reply header
	αXINDENT -9999⊗↔		⊗; flush leading spaces from name
	αXINDENT 1⊗↔αF αβ\,⊗↔		⊗; add a comma at the front
	⊗↔				⊗; move on to the next name
αβ⊗↓

αXDEFINE RPSN2D⊗↔
	αXARGUMENT REPLIN⊗↔αXSSLINE⊗↔	⊗; search from name list to reply-text
	αF⊗↓≡⊗↔Reply-Subject:⊗↓⊗↔	⊗; try to find subject (if none, don't object)
	⊗↔αF:αβ\ ⊗↔αXBREAK SRCHAR.⊗↔αβD	⊗; flush header name
	αXINDENT -9999⊗↔αAαXSUBTRACT REPLIN⊗↔	⊗; pick up subject (moves reply-text line)
	αXARGUMENT REPLIN⊗↔αL		⊗; go to reply-text header
	αXNONEMPTY⊗↔αE			⊗; put subject down at top of actual text
	αXARGUMENT REPLN2⊗↔αLαFMAILαβ\MAIL/SUBJ⊗↔	⊗; make MAIL use top text line as subject
αβ⊗↓

αXDEFINE REPSN3⊗↔
	αXSET REPTMP=CHARS.⊗↔		⊗; length of MAIL command
	α1α5α9αXDIVIDE REPTMP⊗↔		⊗; assume E's limit is 158 chars
	αXMINIMUM REPTMP⊗↔		⊗; reduce to 0 or 1
	αXARGUMENT REPTMP⊗↔αXCASE RPSN3A RPSN3B⊗↔	⊗; do the right thing
	αβK				⊗; put text into undelete buffer
αβ⊗↓

αXDEFINE RPSN3A⊗↔
	⊗↔α1αβ⊗↔⊗⊗↔αβUα1αβ⊗↔⊗αXαβ3αβAαXREDEFINE REPTMP⊗↔αβK	⊗; put MAIL command into macro
	αZREXIT1⊗↔			⊗; prepare to exit
	α∞αβ!αAαZREPTMP⊗↔		⊗; pick up rest of page and mail it
	αZRPSN3C⊗↔			⊗; do a cancel if W flag was originally off
αβ⊗↓

⊗⊂	Here comes the real klugey part!  If the MAIL command is too long to fit
in E's extended command buffer, we need to create a distribution-list file.  This
leads to various problems, such as:
(1) We need to be sure we can write the file (i.e., that the directory won't be
    protected against us), but we have no way of finding out the user's login ppn.
(2) We'd like to be sure the file won't conflict with any other file, in particular
    that it won't overwrite a reply-dist file created by the same user from another
    job.
(3) We'd like to delete the file afterward, but the only files E will delete are
    MSG files on [2,2].
Crockish solution: Since everyone has write-access to [2,2], put the file there,
generating a random name of the form $XXXX$.MSG where the X's are based on the
amount of incore text, the page number, and the line number.  A secondary problem
is making sure that MAIL is done with the file before we delete it.  We execute a
null macro 15000 times, which seems to take a minimum of 1 compute sec, giving
MAIL time at least to start reading it, and then we wait until we're able to
OPEN the file again. ⊗⊃

αXDEFINE RPSN3B⊗↔
	αXSET REPTMP=CORCHS.⊗↔α1αβ⊗↔αβ2αβZRPS3B1⊗↔	⊗; first two chars are incore-#chars mod 676
	αXSET REPTMP=CORLIN.⊗↔αβZRPS3B1⊗↔	⊗; then comes incore-line mod 26
	αXSET REPTMP=PAGE.⊗↔αβZRPS3B1⊗↔		⊗; and finally page number mod 26
	α⊗→αI⊗αε↓$α⊗=$↓.MSG[2,2]/C/Q⊗⊗↔αβAαXREDEFINE REPTMP⊗↔αβK	⊗; macro to go to random file
	α∞αβ!αA					⊗; pick up all our stuff
	αZRPSN3C⊗↔αZRPS3B2⊗↔			⊗; cancel if appropriate
	αZREPTMP⊗↔αE				⊗; go to temp file and drop everything
	αF ⊗↔αXBREAK SRCHAR.⊗↔			⊗; break off MAIL{/SUBJ} part
	αI⊗αXα⊗=/LIST⊗⊗↔α⊗→αS/β⊗↔		⊗; add /LIST switch and separate switch(es) from command
	αXATTACH REPTMP⊗↔αE			⊗; fetch macro with this file's name
	 @αS/αK⊗↔αβUα3αAαXREDEFINE REPTMP⊗↔αβK	⊗; create <ctrl>XMAIL @<file>{/SUBJ}/LIST<cr>
	⊗↔α∞αβ!αAαβ.αXCLOSE⊗↔			⊗; pick up all but name-list and write it out
	αZREPTMP⊗↔				⊗; send the mail
	αEαZREXIT1⊗↔				⊗; put text down, prepare EXIT2 macro
	α-αβDα1α5α0α0α0αZRPS3B3⊗↔		⊗; delete mailing list line, twiddle thumbs
	α∞αZRPS3B4⊗↔				⊗; wait until OPEN command succeeds
	α∞α∂αAα-αH				⊗; E will delete the file
αβ⊗↓

αXDEFINE RPS3B1⊗↔
	αXSET REPTM2=REPTMP⊗↔αβ2αβ6αβXDIVIDE REPTMP⊗↔
	αβ2αβ6αβXREMAINDER REPTM2⊗↔αβ6αβ5αβXADD REPTM2⊗↔αβXCHARACTER REPTM2⊗↔
αβ⊗↓

αXDEFINE RPS3B2⊗↔
	αXIFEQ REPLW⊗↔αXIFEQ RMODE.⊗↔	⊗; if W flag was on but /R mode...
	αβXSAY⊗↔αβXSAY Warning -- Changing files temporarily; doing CANCEL due to /R mode.⊗↔
	αXCANCEL⊗↔
αβ⊗↓

αXDEFINE RPS3B3⊗↔
	⊗≠				⊗; waste time to give MAIL chance to start reading dist list
αβ⊗↓

αXDEFINE RPS3B4⊗↔
	αZRPS3B5⊗↔			⊗; aborts us (and our rep count) if file opened
αβ⊗↓

αXDEFINE RPS3B5⊗↔
	αXOPEN⊗↔
	α2αXABORT⊗↔
αβ⊗↓

αXDEFINE RPSN3C⊗↔
	αXIFNE REPLW⊗↔αXCANCEL⊗↔	⊗; undo everything if W flag was off when REPLY called
αβ⊗↓

αXDEFINE CCME⊗↔
	αZRENTRY⊗↔
	αZCCME0⊗↔			⊗; extra nesting level for quieter aborting
	αZEXIT2⊗↔
αβ⊗↓

αXDEFINE CCME0⊗↔
	αXSET REPTMP=LINE.⊗↔		⊗; remember where we were
	αZRPSN1A⊗↔			⊗; look for "replying-to" line
	⊗↔⊗↔αβ⊗↔Reply-cc: .α⊗↔		⊗; add cc-to-oneself
	αXSET REPTM2=REPTMP⊗↔αXARGUMENT LINE.⊗↔αXDIVIDE REPTM2⊗↔	⊗; is REPTMP≥LINE.?
	αXMINIMUM REPTM2⊗↔αXARGUMENT REPTM2⊗↔αXADD REPTMP⊗↔		⊗; if so, incr
	αXARGUMENT REPTMP⊗↔αL		⊗; return to original line
	αZREXIT1⊗↔
αβ⊗↓

αXDEFINE OLDMSG⊗↔
	αZRENTRY⊗↔
	αZOLDMS0⊗↔			⊗; extra nesting level for quieter aborting
	αZEXIT2⊗↔
αβ⊗↓

αXDEFINE OLDMS0⊗↔
	αZRPSN1A⊗↔			⊗; look for "replying-to" line
	⊗↔⊗↔α-α∞αβ!αC			⊗; copy it & everything above (in incore page)
	⊗; (include "replying-to" line to guarantee at least one line, else αβ! barfs)
	αXINDENT S 2⊗↔αXSIN⊗↔		⊗; indent by 2 and change tabs to spaces
	α∞αLαEα1αβ⊗↔α7α0-α⊗→+⊗↔		⊗; append to reply-text, put line across top
	α∞αZOLDMS1⊗↔α7α0-α⊗→+α⊗↔	⊗; put bar down left and line at bottom
	α-αβD⊗↑αZOLDMS3⊗↔		⊗; flush "replying-to" & blank above it (if any)
	α∞αLαZREXIT1⊗↔			⊗; leave cursur at bottom
αβ⊗↓

αXDEFINE OLDMS1⊗↔
	αZOLDMS2⊗↔			⊗; OLDMS2 handles empty lines
	α0αXNONEMPTY⊗↔			⊗; make sure we stop at incore pagemark
	αF αβ\|⊗↔α1αXTIN⊗↔⊗↔		⊗; if not empty, add spike and move on
αβ⊗↓

αXDEFINE OLDMS2⊗↔
	α0αXEMPTY⊗↔			⊗; note that end-of-page is not empty
	 α⊗↔				⊗; create space for OLDMS1 to change
αβ⊗↓

αXDEFINE OLDMS3⊗↔
	αXIFEQ CHARS.⊗↔αβD		⊗; delete line if contains only a "|"
αβ⊗↓

αXDEFINE TOLIST⊗↔
	αZRENTRY⊗↔
	αZTOLST0⊗↔			⊗; extra nesting level for quieter aborting
	αZEXIT2⊗↔
αβ⊗↓

αXDEFINE TOLST0⊗↔
	αZRPSN1A⊗↔⊗↔⊗↔			⊗; look for "replying-to", go to line after
	αZTOLST1⊗↔			⊗; change it to "replying-to"
	α-αβD				⊗; flush old line
	αZREXIT1⊗↔
αβ⊗↓

αXDEFINE TOLST1⊗↔
	α+αXSSLINE⊗↔αXSTOPZERO⊗↔	⊗; prepare for failing substitutions
	αFAlso-To:αβ\Replying-To:⊗↔αXSTOPONE⊗↔αXIFNE NSUBST.⊗↔	⊗; abort if okay
	αXSTOPZERO⊗↔αFReply-cc:αβ\Replying-To:⊗↔αXSTOPONE⊗↔αXIFNE NSUBST.⊗↔
	αβXSAY Sorry -- Line after "Replying-To" isn't an address line.⊗↔
	⊗↑αZREPLX2⊗↔
αβ⊗↓

αxsay REPLY CCME TOLIST OLDMSG ⊗↔

⊗⊂ And we'll be needing ENTRY/EXIT macros: ⊗⊃	αXEXECUTE EINIT.CMD[1,3](13)⊗↔
⊗⊂ DON		Archive a message

The ARCHIV macro moves the current message (as defined by the ∂ command) to an
archive file, creating the file if necessary.  The message is deleted from the
original file only after it has been written out in the archive file.

To use, put the name of the archive file on the current line and execute ARCHIV.
The most likely way to do this is via a macro in your own EINIT file that does:
	αβ⊗↔<filename>αZARCHIV⊗↔
The filename may include a /N switch if desired.
⊗⊃

αXDEFINE ARCHIV⊗↔
	αXSTOPONE⊗↔αXTERSE⊗↔αXSILENT⊗↔
	αZARCHV1⊗↔
	α-αXSILENT⊗↔α-αXTERSE⊗↔αXSTOPALL⊗↔
αβ⊗↓

αXDEFINE ARCHV1⊗↔
	αZARCHV2⊗↔
	αβXSAY Sorry -- No file name found.  Check ARCHIV documentation.⊗↔
	αβD
αβ⊗↓

αXDEFINE ARCHV2⊗↔
	αCαXIFEQ ATTSIZ.⊗↔αEα0αXNONEMPTY⊗↔
	⊗↑αI	⊗αZARCHV5⊗⊗↔	α⊗=	/C⊗⊗↔⊗αE
	αAαXREDEFINE ARCHV4⊗↔αβK
	αI	⊗αε	α⊗=	/E⊗⊗↔⊗αXM⊗⊗↔⊗α2⊗αXABORT⊗⊗↔
	αAαXREDEFINE ARCHV5⊗↔αβK
	αZARCHV3⊗↔
	αβXSAY Sorry -- No message text found.⊗↔
	α2αXABORT⊗↔
αβ⊗↓

αXDEFINE ARCHV3⊗↔
	α∂αCαXIFLE ATTSIZ.⊗↔αZARCHV4⊗↔
	αβXSAY⊗↔αXARGUMENT LINES.⊗↔αXSAY⊗↔
	αXARGUMENT PAGE.⊗↔αXSAY  lines moved to page ⊗↔αXSAY .⊗↔
	αH⊗↑α∂αβD
	α3αXABORT⊗↔
αβ⊗↓

αxsay ARCHIV ⊗↔
⊗⊂ DON		Purge selected pages from a file, such as BBOARD

The first time it's executed, PURGE scans the current page for all lines that
look like E directory lines, collects them, and sorts them.  It then stops to
let you look them over.  When executed a second time, it deletes the pages for
which directory lines were gathered, highest-numbered first.  Before deleting
each page, it verifies that the current directory line from page 1 is the same
as the one from the purge list (except perhaps for the disk record number); if
not, the page is skipped.  Before each page is deleted, you're shown the text
from the directory line along with the top line of the page, for a visual
double-check in case the automatic directory-line comparison fails; hit ESCAPE-I
if they don't match!!  The page with the purge list is not deleted as part of
this pass.  After deleting the selected pages, the macro stops and shows you an
account of what was done, pointing out how many pages (if any) were spared due
to directory-line mismatch.  If you like the results, hit ⊗Y to execute the
macro a third time, whereupon it will delete the purge-list page and burp the
file (using the BELCH macro elsewhere in this CMD file).
⊗⊃

αXDEFINE PURGE⊗↔
	αβ#αXSET PURGEX⊗↔	⊗; discard repeat arg to guarantee 3-step execution
	αβXARGUMENT PURGEV⊗↔αXCASE PURGE0 PURGE1 PURGE2⊗↔
	αXADD PURGEV⊗↔αβ3αXREMAINDER PURGEV⊗↔
αβ⊗↓

αXDEFINE PURGE0⊗↔
	αXREADWRITE⊗↔αXOPEN⊗↔α-αXAUTOBURP⊗↔αXTHISPAGE⊗↔α∞αLβ⊗→
	αXSTOPONE⊗↔αXSILENT⊗↔αXTERSE⊗↔α-αXCHECK⊗↔
	α0αXSET PURGEX⊗↔αβLαXARGUMENT LINES.⊗↔αZPURG0A⊗↔
	αXEXECUTE EINIT.CMD[1,3](11:12)⊗↔αZQNOSHO⊗↔αZQSORT⊗↔αLα∞αZPURG0D⊗↔
	αLα-αβDαβ⊗↔⊗↔If you type ⊗⊗Y, the following pages will be deleted:⊗↔αβUαJ
	αXSTOPALL⊗↔αXCHECK⊗↔α-αXTERSE⊗↔α-αXSILENT⊗↔
αβ⊗↓

αXDEFINE PURG0A⊗↔
	αXADD PURGEX⊗↔αXARGUMENT PURGEX⊗↔αβLαCα∞αβLαEαZPURG0B⊗↔α⊗↔α∞αβD
αβ⊗↓

αXDEFINE PURG0B⊗↔
	α6α7αXIFEQ ASCII.⊗↔α1α2αXIFLE CHARS.⊗↔αCαEαβ⊗↔⊗=XαβUαXJOIN⊗↔αXBREAK 16⊗↔
	α αβ5αZPURG0C⊗↔αβ6αXIFEQ CHAR.⊗↔αβ3αβ2αXIFEQ ASCII.⊗↔
	α αβ5αZPURG0C⊗↔αβ1αβ2αXIFEQ CHAR.⊗↔αβ9αXIFEQ ASCII.⊗↔
	αK⊗↔α5α⊗↑αL⊗↔⊗↔αβD⊗↑αXJOIN⊗↔⊗↔
αβ⊗↓

αXDEFINE PURG0C⊗↔
	αβ4αβ8αXIFLE ASCII.⊗↔αβ5αβ7αXIFGE ASCII.⊗↔α 
αβ⊗↓

αXDEFINE PURG0D⊗↔
	αXBREAK 5⊗↔αβD⊗↔
αβ⊗↓

αXDEFINE PURGE1⊗↔
	αXSTOPONE⊗↔αXSILENT⊗↔αXTERSE⊗↔α-αXCHECK⊗↔α3αXATTSET⊗↔α0αXSET PURGEZ⊗↔
	αXZMARKS⊗↔α∞αLαβMβ⊗↔α-αXNONEMPTY⊗↔α2⊗↔α∞αβD⊗↑α∞αZPURG1A⊗↔αXZMARKS⊗↔
	α8αXATTSET⊗↔αXSTOPALL⊗↔αXCHECK⊗↔α-αXTERSE⊗↔α-αXSILENT⊗↔
	α-αβDαβ⊗↔αZPURGEZ⊗↔αβ2αXMINIMUM PURGEZ⊗↔
	αXARGUMENT PURGEZ⊗↔αXCASE PURGZ0 PURGZ1 PURGZ2⊗↔α⊗↔α0α!⊗↔αJ
αβ⊗↓

αXDEFINE PURG1A⊗↔
	⊗↑α0αXNONEMPTY⊗↔αCαEαβ⊗↔⊗=⊗=⊗=αβUαXJOIN⊗↔αXBREAK 16⊗↔αK αDαβAαXTIN⊗↔
	αXREDEFINE PURGEX⊗↔αβKαCα+αAαZPURG1B⊗↔αβKαMα-αXEMPTY⊗↔α-αA⊗↔αE
	⊗; hairy computation yields 1/2/4/3 for PURGEX=0/1/PAGE./other
	αXSET PURGEY=PURGEX⊗↔αXARGUMENT PAGE.⊗↔αXSUBTRACT PURGEY⊗↔
	αXARGUMENT PURGEY⊗↔αXMULTIPLY PURGEY⊗↔αXMINIMUM PURGEY⊗↔
	α2αXMINIMUM PURGEX⊗↔α2αXADD PURGEX⊗↔αXARGUMENT PURGEY⊗↔αXSUBTRACT PURGEX⊗↔
	αβ⊗↔\/Deleted:/Can't delete page 1!/**SPARED**/Postponed:/α⊗→
	αβXARGUMENT PURGEX⊗↔αK/αDαS/αK⊗↔⊗=α⊗↔αXJOIN⊗↔⊗↑
αβ⊗↓

αXDEFINE PURG1B⊗↔
	αXIFNE PURGEX⊗↔αXARGUMENT PURGEX⊗↔αXIFNE PAGE.⊗↔αXADD PURGEZ⊗↔
	α1αPα2αXARGUMENT PURGEX⊗↔αLα+αCαXARGUMENT PURGEX⊗↔αβPα∞αLαXTIN⊗↔αXSIN⊗↔
	αE⊗↔αXSET PURGEY=CHARS.⊗↔⊗↔αXARGUMENT CHARS.⊗↔αXSUBTRACT PURGEY⊗↔
	α2⊗↑α3αAα0αXIFEQ PURGEY⊗↔αE⊗↔αXSET PURGEY=CHARS.⊗↔α7αXSUBTRACT PURGEY⊗↔
	αXBREAK 6⊗↔αβD⊗↔αXBREAK⊗↔αβD⊗↑αXARGUMENT PURGEY⊗↔αZPURG1C⊗↔α2αβDα-αA
	α0αXIFEQ PURGEY⊗↔αEαLα∞αAα1αVαEα∞α∂αAα0αXSET PURGEX⊗↔αXSUBTRACT PURGEZ⊗↔
αβ⊗↓

αXDEFINE PURG1C⊗↔
	αXSET PURGEY=ASCII.⊗↔αXBREAK 1⊗↔αβD⊗↔αXARGUMENT ASCII.⊗↔αXSUBTRACT PURGEY⊗↔
	αXBREAK⊗↔αβD⊗↑α0αXIFEQ PURGEY⊗↔
αβ⊗↓

αXDEFINE PURGZ0⊗↔
	α⊗→No problems encountered; type ⊗⊗Y to delete this page and finish up.
αβ⊗↓

αXDEFINE PURGZ1⊗↔
	 page left undeleted due to directory-line mismatch; check the list⊗↔
	below and, when satisfied, type ⊗⊗Y to delete this page and finish up.
αβ⊗↓

αXDEFINE PURGZ2⊗↔
	 pages left undeleted due to directory-line mismatches; check the list⊗↔
	below and, when satisfied, type ⊗⊗Y to delete this page and finish up.
αβ⊗↓

αXDEFINE PURGE2⊗↔
	αLα∞α∂αβDαβXSAY⊗↔α1α9αXAUTOBURP⊗↔αZBELCH⊗↔
αβ⊗↓

αβ0αXSET PURGEV⊗↔

αxsay PURGE ⊗↔
⊗⊂ DON		Find out the name of the file being edited

The NAME macro puts into the attach buffer a line containing the name of
the file currently being edited.  The attach buffer is assumed to be empty
to begin with.  No other significant side effects should occur; in particular,
the "W" flag in the header does not get set by executing this macro.  The
name will have extraneous blanks removed; this results in an incorrect
name if there are leading or internal blanks in the name or extension.
However, the most common case of this is files on [2,2], and these are
handled as a special case so they come out okay.
⊗⊃

αXDEFINE NAME⊗↔
	αXSILENT⊗↔αXTERSE⊗↔αXSUBJOB⊗↔αXLATTACH⊗↔αXSET NAMEWF=WFLAG.⊗↔
	α0α=tt w⊗↔α+α3αXLRECEIVE⊗↔	⊗; ask for wholine, wait for output
	α∞αXJOIN⊗↔αEpj ttyα4αDα3α αK⊗↔	⊗; create pj tty# command
	αβAα=αβKα+α3αXLRECEIVE⊗↔	⊗; send that, wait for output
	α1αβKα∞αXJOIN⊗↔αEfileαK α αS αK⊗↔	⊗; create file <parent> command
	αβAα=αβKα+α2αXLRECEIVE⊗↔	⊗; send that, wait for output
	α∞αXJOIN⊗↔αEαK ∂α6α .α3α [α3α β,α3α ]αK⊗↔∂   α⊗↔	⊗; add formatting
	αF∂   αβ\∂∂⊗↔αDαS∂αK⊗↔		⊗; handle [2,2] files
	αβAαXJFILL 0,0,1⊗↔α∞αXJOIN⊗↔	⊗; remove all blanks
	αXARGUMENT NAMEWF⊗↔αXCASE NAMEW0 NAMEW1⊗↔	⊗; CANCEL if appropriate
	α-αXTERSE⊗↔α-αXSILENT⊗↔α-αXSUBJOB⊗↔
αβ⊗↓

αXDEFINE NAMEW0⊗↔
	αXCANCEL⊗↔
αβ⊗↓

αXDEFINE NAMEW1⊗↔
	⊗≠
αβ⊗↓

αxsay NAME ⊗↔
⊗⊂ RSF		Send newly added BBOARD messages to "OTHER-SU-BBOARDS".

The OBBD macro can be used to conveniently forward appended BBOARD messages
to "OTHER-SU-BBOARDS". To use it, move the arrow to a line that begins
with a PPN (either 2 characters or 3) followed by " - ". (Note that the
PPN doesn't have to be yours, although it typically will be.) The attach
buffer should be empty to begin with. On executing the macro, the text on
this and the following lines will be mailed to OTHER-SU-BBOARDS.

In addition, the macro automatically does the following:
	(i)	The mail that it sends will have a subject line. This subject
		is that of the first message that appears on the page (prefixed
		by "re: "). The subject line will also indicate that the mail
		came from SAIL's BBOARD.
	(ii)	It performs a αXNDBBOARD command (and deletes the old 
		header line).
	(iii)	It adds a note at the bottom of the page saying what lines have
		been sent to OTHER-SU-BBOARDS.

The macro can fail for only three reasons (as far as I know):
	(i)	The arrow is not initially pointing to a line beginning
		with "xy - " or "xyz - ". The macro uses this as a safety
		check - it helps safeguard against accidentally forwarding
		the wrong lines of text.
	(ii)	The first message on the page does not have a subject field
		(either in the header line or in a separate "Subject:" line).
		In this case you will be asked to add a subject to the header
		line before resuming.
	(iii)	The first line on the page is not a message header.
		In this case, you lose.
⊗⊃



αXDEFINE OBBD⊗↔
	αXSILENT⊗↔αXTERSE⊗↔
	αZOBB1⊗↔	⊗; This extra level of nesting leads to cleaner error recovery.
	α-αXSILENT⊗↔α-αXTERSE⊗↔
αβ⊗↓

αXDEFINE OBB1⊗↔
	αZOBBCHK⊗↔			⊗; Make sure that the arrow line is OK.
	αXSET MSGLIN=LINE.⊗↔		⊗; Remember this position.
	αZOBBSUB⊗↔			⊗; Find the subject.
	αXARGUMENT MSGLIN⊗↔αL		⊗; Move the subject line back here.
	α∞αAαXMAIL OTHER-SU-BBOARDS/SU⊗↔⊗; Actually send off the message.
	αEαβD				⊗; Get rid of the subject line.
	αXNDBBOARD⊗↔⊗↔αβD		⊗; Do αXNDBBOARD, etc.
	αZOBBNOT⊗↔			⊗; Add a notice at the bottom of the page.
αβ⊗↓

αXDEFINE OBBCHK⊗↔
	αXSTOPONE⊗↔
	α3α αZOBBHCH⊗↔			⊗; Check for " - " starting from the 4th char.
	α⊗↔α2α αZOBBHCH⊗↔		⊗; If not, then check for " - " starting from the 3rd char.
	α⊗↔αXSAY This line doesn't seem to begin with a PPN!⊗↔
	αXBEEPME⊗↔α2αXABORT⊗↔		⊗; Abort (to OBBD).
αβ⊗↓

αXDEFINE OBBHCH⊗↔
	αβ3αβ2αXIFEQ ASCII.⊗↔		⊗; Check for " ". (Note that we need the βs)
	α αβ4αβ5αXIFEQ ASCII.⊗↔		⊗; Check for "-".
	α αβ3αβ2αXIFEQ ASCII.⊗↔		⊗; Check for " ".
	α⊗↔α2αXABORT⊗↔			⊗; Success! Abort OBBCHK.
αβ⊗↓

αXDEFINE OBBSUB⊗↔	⊗; Note: much of this was copied from DON's REPLY macro.
	αLαXEMPTY⊗↔α+α0αXSSLINE⊗↔	⊗; searches stop before first blank line
	αXSTOPZERO⊗↔αLαF⊗↓≡⊗↔Subject:⊗↓⊗↔αXSTOPONE⊗↔	⊗; look for RFC733 subject line
	αXARGUMENT NFOUND.⊗↔αXCASE OBBS1 OBBS2⊗↔
	αXSTOPZERO⊗↔α+αXSSLINE⊗↔αFre: re:αβ\re:⊗↔	⊗; Delete redundant "re: " (if any).
	α⊗= (from SAIL's BBOARD)
	αA				⊗; Now grab onto the subject.
αβ⊗↓

αXDEFINE OBBS1⊗↔			⊗; Looks for a subject in the header line.
	αZOBBS1A⊗↔			⊗; try for "∂" line (aborts OBBS1 if succeeds)
	αL∂α⊗=⊗=αXSAY No subject found! Put one here, then go back and try again.⊗↔
	αXBEEPME⊗↔αβ3αXABORT⊗↔		⊗; Abort (to OBBD). (Note: it must be αβ3)
αβ⊗↓

αXDEFINE OBBS1A⊗↔
	α1α5αXIFEQ ASCII.⊗↔			⊗; check top line for "∂"
	α+αXSSLINE⊗↔α2αF⊗=⊗↔			⊗; does line include two tabs?
	α+α1αXARGUMENT SRCHAR.⊗↔αXIFLT CHARS.⊗↔	⊗; and does second tab have stuff after it?
	αCαEαXSSLINE⊗↔αF⊗=αβ\  αβ2⊗↔		⊗; a winner!  copy it; tabs -> dbl-space
	αXBREAK SRCHAR.⊗↔			⊗; break between second pair of spaces
	αβDα1αβ⊗↔re:α⊗↔αXJOIN⊗↔			⊗; create our subject line
	αAαXTIN⊗↔αXSIN⊗↔αE			⊗; flush trailing blanks
	α2αXABORT⊗↔				⊗; abort OBBS1
αβ⊗↓

αXDEFINE OBBS2⊗↔
	⊗↔αCαEαFSubject:αβ\re:⊗↔⊗↑⊗↔		⊗; copy RFC733 subject line and make it ours
αβ⊗↓

αXDEFINE OBBNOT⊗↔
	αQαKα⊗=αKα αDα⊗=αLα⊗=⊗=α⊗→αSα⊗=αKα⊗↔αA	⊗; Isolate (and attach) your own PPN.
	α∞αLαEαβ⊗↔α⊗↔⊗↔				⊗; Take it to the bottom, and insert a blank line.
						⊗; Now create the notice:
	β[α⊗= - Forwarded to OTHER-SU-BBOARDS from line αZMSGLIN⊗↔]αβ⊗↔α⊗↔
αβ⊗↓